@opencharacter/swn-revised 0.0.0-stage → 0.1.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 (302) hide show
  1. package/LICENSE +147 -0
  2. package/README.md +128 -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 +7 -0
  42. package/content/classes/expert.yaml +14 -0
  43. package/content/classes/psychic.yaml +11 -0
  44. package/content/classes/warrior.yaml +27 -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 +18 -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 +20 -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/partial-classes/expert.yaml +5 -0
  160. package/content/partial-classes/psychic.yaml +18 -0
  161. package/content/partial-classes/warrior.yaml +7 -0
  162. package/content/techniques/accelerated-succor.yaml +10 -0
  163. package/content/techniques/alternate-outcome.yaml +10 -0
  164. package/content/techniques/anguished-vision.yaml +10 -0
  165. package/content/techniques/burdened-apportation.yaml +10 -0
  166. package/content/techniques/cloak-powers.yaml +10 -0
  167. package/content/techniques/concert-of-minds.yaml +10 -0
  168. package/content/techniques/cursed-luck.yaml +59 -0
  169. package/content/techniques/deep-intrusion.yaml +10 -0
  170. package/content/techniques/destinys-shield.yaml +10 -0
  171. package/content/techniques/effortless-apportation.yaml +10 -0
  172. package/content/techniques/facile-mind.yaml +10 -0
  173. package/content/techniques/far-thought.yaml +10 -0
  174. package/content/techniques/flawless-mastery.yaml +10 -0
  175. package/content/techniques/force-puppetry.yaml +10 -0
  176. package/content/techniques/forced-outcome.yaml +10 -0
  177. package/content/techniques/holistic-optimization-patterning.yaml +10 -0
  178. package/content/techniques/impact-sump.yaml +10 -0
  179. package/content/techniques/impervious-pavis-of-will.yaml +10 -0
  180. package/content/techniques/intuitive-response.yaml +10 -0
  181. package/content/techniques/invincible-stand.yaml +10 -0
  182. package/content/techniques/kinetic-transversal.yaml +10 -0
  183. package/content/techniques/major-organ-restoration.yaml +10 -0
  184. package/content/techniques/mastered-succor.yaml +10 -0
  185. package/content/techniques/memory-editing.yaml +10 -0
  186. package/content/techniques/metadimensional-friction.yaml +10 -0
  187. package/content/techniques/metamorph.yaml +10 -0
  188. package/content/techniques/mindtracing.yaml +10 -0
  189. package/content/techniques/neural-trap.yaml +10 -0
  190. package/content/techniques/not-my-time.yaml +10 -0
  191. package/content/techniques/offensive-apportation.yaml +10 -0
  192. package/content/techniques/oracle.yaml +6 -0
  193. package/content/techniques/organic-purification-protocols.yaml +10 -0
  194. package/content/techniques/perceptive-dislocation.yaml +10 -0
  195. package/content/techniques/personal-apportation.yaml +6 -0
  196. package/content/techniques/pressure-field.yaml +10 -0
  197. package/content/techniques/proficient-apportation.yaml +10 -0
  198. package/content/techniques/prophecy.yaml +10 -0
  199. package/content/techniques/psychic-refinement.yaml +11 -0
  200. package/content/techniques/psychic-static.yaml +10 -0
  201. package/content/techniques/psychic-succor.yaml +39 -0
  202. package/content/techniques/psychic-tutelage.yaml +10 -0
  203. package/content/techniques/quintessential-reconstruction.yaml +10 -0
  204. package/content/techniques/reactive-telekinesis.yaml +10 -0
  205. package/content/techniques/reflex-response.yaml +10 -0
  206. package/content/techniques/remote-repair.yaml +10 -0
  207. package/content/techniques/rift-reduplication.yaml +10 -0
  208. package/content/techniques/sense-the-need.yaml +10 -0
  209. package/content/techniques/slip-field.yaml +10 -0
  210. package/content/techniques/spatial-awareness.yaml +10 -0
  211. package/content/techniques/spatial-synchrony-mandala.yaml +10 -0
  212. package/content/techniques/stutterjump.yaml +10 -0
  213. package/content/techniques/suppress-cognition.yaml +10 -0
  214. package/content/techniques/surge-momentum.yaml +10 -0
  215. package/content/techniques/suspended-manifestation.yaml +10 -0
  216. package/content/techniques/synthetic-adaptation.yaml +10 -0
  217. package/content/techniques/tangible-force-construct.yaml +10 -0
  218. package/content/techniques/telekinetic-armory.yaml +10 -0
  219. package/content/techniques/telekinetic-expertise.yaml +10 -0
  220. package/content/techniques/telekinetic-flight.yaml +10 -0
  221. package/content/techniques/telekinetic-manipulation.yaml +6 -0
  222. package/content/techniques/telekinetic-ram.yaml +10 -0
  223. package/content/techniques/telepathic-assault.yaml +10 -0
  224. package/content/techniques/telepathic-contact.yaml +6 -0
  225. package/content/techniques/teratic-overload.yaml +10 -0
  226. package/content/techniques/terminal-reflection.yaml +10 -0
  227. package/content/techniques/thermokinesis.yaml +10 -0
  228. package/content/techniques/tissue-integrity-field.yaml +10 -0
  229. package/content/techniques/transmit-thought.yaml +10 -0
  230. package/content/techniques/unity-of-thought.yaml +10 -0
  231. package/content/templates/trained-unarmed.yaml +9 -0
  232. package/content/weapons/advanced-bow.yaml +15 -0
  233. package/content/weapons/anti-vehicle-laser.yaml +18 -0
  234. package/content/weapons/combat-rifle.yaml +18 -0
  235. package/content/weapons/combat-shotgun.yaml +18 -0
  236. package/content/weapons/conversion-bow.yaml +15 -0
  237. package/content/weapons/crude-pistol.yaml +18 -0
  238. package/content/weapons/demo-charge.yaml +13 -0
  239. package/content/weapons/distortion-cannon.yaml +18 -0
  240. package/content/weapons/grenade.yaml +14 -0
  241. package/content/weapons/heavy-machine-gun.yaml +19 -0
  242. package/content/weapons/hydra-array.yaml +18 -0
  243. package/content/weapons/knife.yaml +7 -0
  244. package/content/weapons/large-advanced-weapon.yaml +13 -0
  245. package/content/weapons/large-primitive-weapon.yaml +12 -0
  246. package/content/weapons/laser-pistol.yaml +18 -0
  247. package/content/weapons/laser-rifle.yaml +19 -0
  248. package/content/weapons/mag-pistol.yaml +17 -0
  249. package/content/weapons/mag-rifle.yaml +17 -0
  250. package/content/weapons/medium-advanced-weapon.yaml +13 -0
  251. package/content/weapons/medium-primitive-weapon.yaml +12 -0
  252. package/content/weapons/monoblade-knife.yaml +7 -0
  253. package/content/weapons/monoblade-sword.yaml +4 -0
  254. package/content/weapons/musket.yaml +18 -0
  255. package/content/weapons/plasma-projector.yaml +18 -0
  256. package/content/weapons/primitive-bow.yaml +15 -0
  257. package/content/weapons/railgun.yaml +18 -0
  258. package/content/weapons/revolver.yaml +17 -0
  259. package/content/weapons/rifle.yaml +17 -0
  260. package/content/weapons/rocket-launcher.yaml +18 -0
  261. package/content/weapons/semi-auto-pistol.yaml +17 -0
  262. package/content/weapons/shear-rifle.yaml +19 -0
  263. package/content/weapons/shotgun.yaml +17 -0
  264. package/content/weapons/small-advanced-weapon.yaml +14 -0
  265. package/content/weapons/small-primitive-weapon.yaml +13 -0
  266. package/content/weapons/sniper-rifle.yaml +17 -0
  267. package/content/weapons/spear.yaml +8 -0
  268. package/content/weapons/spike-thrower.yaml +18 -0
  269. package/content/weapons/stun-baton.yaml +14 -0
  270. package/content/weapons/submachine-gun.yaml +18 -0
  271. package/content/weapons/suit-ripper.yaml +11 -0
  272. package/content/weapons/thermal-knife.yaml +7 -0
  273. package/content/weapons/thermal-pistol.yaml +18 -0
  274. package/content/weapons/thunder-gun.yaml +18 -0
  275. package/content/weapons/unarmed.yaml +8 -0
  276. package/content/weapons/void-carbine.yaml +17 -0
  277. package/content/weapons/vortex-cannon.yaml +16 -0
  278. package/content/weapons/wheatcutter-belt.yaml +16 -0
  279. package/dist/i18n/en.d.ts +3 -0
  280. package/dist/i18n/en.js +2 -0
  281. package/dist/i18n/en.json +1356 -0
  282. package/dist/index.d.ts +3 -0
  283. package/dist/index.js +2 -0
  284. package/dist/release.json +30238 -0
  285. package/i18n/en/content.yaml +394 -0
  286. package/i18n/en/foci.yaml +199 -0
  287. package/i18n/en/rules.yaml +759 -0
  288. package/i18n/en/text.yaml +249 -0
  289. package/i18n/en.yaml +1 -0
  290. package/pack.yaml +15 -0
  291. package/package.json +58 -3
  292. package/rules/advancement.yaml +461 -0
  293. package/rules/character.yaml +114 -0
  294. package/rules/checks.yaml +160 -0
  295. package/rules/combat.yaml +312 -0
  296. package/rules/core.yaml +111 -0
  297. package/rules/creation.yaml +633 -0
  298. package/rules/gear.yaml +176 -0
  299. package/rules/layout.yaml +195 -0
  300. package/rules/psionics.yaml +105 -0
  301. package/rules/start.yaml +403 -0
  302. package/rules/tags.yaml +60 -0
@@ -0,0 +1,160 @@
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
+ - { id: success, when: 'flags.difficulty >= 0 && roll.total >= flags.difficulty' }
31
+ - { id: failure, when: 'flags.difficulty >= 0' }
32
+ - { id: rolled, when: true }
33
+ # A natural 1 always fails and a natural 20 always succeeds.
34
+ save:
35
+ - {
36
+ id: success,
37
+ when: 'roll.faces[0] == 20 || (roll.faces[0] != 1 && roll.total >= flags.target)',
38
+ }
39
+ - { id: failure, when: true }
40
+ attack:
41
+ - { id: hit, when: 'flags.ac >= 0 && roll.total >= flags.ac' }
42
+ - { id: miss, when: 'flags.ac >= 0' }
43
+ - { id: rolled, when: true }
44
+
45
+ actions:
46
+ # 2d6 + skill + attribute modifier; unskilled is -1. Some foci roll more dice and keep two.
47
+ - id: skill-check
48
+ tags: [check]
49
+ params:
50
+ skill:
51
+ type: enum
52
+ required: true
53
+ values:
54
+ &skills [
55
+ administer,
56
+ connect,
57
+ exert,
58
+ fix,
59
+ heal,
60
+ know,
61
+ lead,
62
+ notice,
63
+ perform,
64
+ pilot,
65
+ program,
66
+ punch,
67
+ shoot,
68
+ sneak,
69
+ stab,
70
+ survive,
71
+ talk,
72
+ trade,
73
+ work,
74
+ biopsionics,
75
+ metapsionics,
76
+ precognition,
77
+ telekinesis,
78
+ telepathy,
79
+ teleportation,
80
+ ]
81
+ attribute: { type: enum, required: true, values: [str, dex, con, int, wis, cha] }
82
+ difficulty: { type: integer, optional: true, min: 0 }
83
+ results: { bands: check }
84
+ steps:
85
+ - id: start
86
+ kind: branch
87
+ cases:
88
+ - when: true
89
+ flags:
90
+ difficulty: 'has(params.difficulty) ? params.difficulty : -1'
91
+ reroll: false
92
+ - id: check
93
+ kind: roll
94
+ tags: &checkTags
95
+ - check
96
+ - formula: >-
97
+ ['check.' + params.skill]
98
+ + (params.skill in ['connect', 'lead', 'perform', 'talk'] ? ['check.social'] : [])
99
+ bands: check
100
+ parts: &checkParts
101
+ - dice: "(fieldOf('skills.{skill}.dice', params.skill))d6kh2"
102
+ - value: "fieldOf('skills.{skill}.level', params.skill)"
103
+ - value: "fieldOf('attributes.{attr}.mod', params.attribute)"
104
+ - id: retry
105
+ kind: choice
106
+ tags: [failed-check]
107
+ when: "steps.check.band == 'failure'"
108
+ options: [{ id: accept }]
109
+ recommend: "'accept'"
110
+ - id: reroll
111
+ kind: roll
112
+ when: flags.reroll
113
+ tags: *checkTags
114
+ bands: check
115
+ parts: *checkParts
116
+ - id: result
117
+ kind: outcome
118
+ result: >-
119
+ has(steps.reroll) && steps.reroll.band == 'success' ? 'success' : steps.check.band
120
+ data:
121
+ total: 'has(steps.reroll) ? max(steps.check.total, steps.reroll.total) : steps.check.total'
122
+
123
+ - id: saving-throw
124
+ tags: [save]
125
+ params:
126
+ save: { type: enum, required: true, values: [physical, evasion, mental] }
127
+ modifier: { type: integer, default: 0 }
128
+ results: { bands: save }
129
+ steps:
130
+ - id: start
131
+ kind: branch
132
+ cases:
133
+ - when: true
134
+ flags:
135
+ target: >-
136
+ params.save == 'physical' ? saves.physical
137
+ : params.save == 'evasion' ? saves.evasion : saves.mental
138
+ - id: save
139
+ kind: roll
140
+ tags: [save, { formula: "'save.' + params.save" }]
141
+ bands: save
142
+ parts:
143
+ - dice: 1d20
144
+ - value: params.modifier
145
+ - { id: result, kind: outcome, result: steps.save.band }
146
+
147
+ - id: initiative
148
+ tags: [initiative]
149
+ results: [rolled]
150
+ steps:
151
+ - id: roll
152
+ kind: roll
153
+ tags: [initiative]
154
+ parts:
155
+ - dice: 1d8
156
+ - value: attributes.dex.mod
157
+ - id: result
158
+ kind: outcome
159
+ result: "'rolled'"
160
+ data: { total: steps.roll.total }
@@ -0,0 +1,312 @@
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
+ kind: changes
183
+ changes:
184
+ - { type: adjust, field: hp.current, by: level, when: hp.current > 0, tags: [healing] }
185
+ - { type: adjust, field: strain.current, by: -1, when: strain.current > 0 }
186
+ - { type: set, field: effort.day, value: 0 }
187
+ - { type: set, field: effort.scene, value: 0 }
188
+ - { type: set, field: effort.torched, value: 0 }
189
+ - { type: set, field: scene.expertReroll, value: false }
190
+ - { type: set, field: scene.warriorLuck, value: false }
191
+ - { id: result, kind: outcome, result: "'rested'" }
192
+
193
+ - id: end-scene
194
+ tags: [health]
195
+ results: [ended]
196
+ steps:
197
+ - id: reset
198
+ kind: changes
199
+ changes:
200
+ - { type: set, field: effort.scene, value: 0 }
201
+ - { type: set, field: effort.torched, value: 0 }
202
+ - { type: set, field: scene.expertReroll, value: false }
203
+ - { type: set, field: scene.warriorLuck, value: false }
204
+ - { id: result, kind: outcome, result: "'ended'" }
205
+
206
+ # A stim or drug on yourself: it fails if its System Strain would pass Constitution.
207
+ - id: use-drug
208
+ tags: [health]
209
+ available: "item.category == 'pharmaceutical' && self.quantity > 0"
210
+ results: [applied, failed]
211
+ steps:
212
+ - id: start
213
+ kind: branch
214
+ cases:
215
+ - when: true
216
+ flags:
217
+ fits: strain.total + item.strain <= strain.max
218
+ - id: heal
219
+ kind: roll
220
+ when: flags.fits && has(item.heal)
221
+ tags: [healing]
222
+ parts:
223
+ - dice: item.heal
224
+ - value: 'item.healAddsSkill ? max(0, skills.heal.level) : 0'
225
+ - id: apply
226
+ kind: changes
227
+ changes:
228
+ - { type: adjustQuantity, entry: self, by: -1 }
229
+ - {
230
+ type: adjust,
231
+ field: strain.current,
232
+ by: item.strain,
233
+ when: flags.fits && item.strain > 0,
234
+ }
235
+ - type: adjust
236
+ when: has(steps.heal)
237
+ field: hp.current
238
+ by: steps.heal.total
239
+ tags: [healing]
240
+ - { id: result, kind: outcome, result: "flags.fits ? 'applied' : 'failed'" }
241
+
242
+ - id: trigger-cyberware
243
+ tags: [strain]
244
+ available: item.activationStrain > 0
245
+ results: [triggered, failed]
246
+ steps:
247
+ - id: start
248
+ kind: branch
249
+ cases:
250
+ - when: true
251
+ flags:
252
+ fits: strain.total + item.activationStrain <= strain.max
253
+ - id: strain
254
+ kind: changes
255
+ when: flags.fits
256
+ changes:
257
+ - { type: adjust, field: strain.current, by: item.activationStrain }
258
+ - { id: result, kind: outcome, result: "flags.fits ? 'triggered' : 'failed'" }
259
+
260
+ # Commit a point of Effort for the scene or for the day.
261
+ - id: commit-effort
262
+ tags: [psionics]
263
+ available: effort.available > 0
264
+ params:
265
+ until: { type: enum, values: [scene, day], default: scene }
266
+ results: [committed]
267
+ steps:
268
+ - id: commit
269
+ kind: changes
270
+ changes:
271
+ - { type: adjust, field: effort.scene, by: 1, when: "params.until == 'scene'" }
272
+ - { type: adjust, field: effort.day, by: 1, when: "params.until == 'day'" }
273
+ - { id: result, kind: outcome, result: "'committed'" }
274
+
275
+ # Torching: a free point of Effort for the scene, at a risk to Wisdom or Constitution.
276
+ - id: torch
277
+ tags: [psionics]
278
+ available: "psionics.access != 'none'"
279
+ results: [harmless, wisdom, constitution, chosen]
280
+ steps:
281
+ - id: roll
282
+ kind: roll
283
+ tags: [torch]
284
+ parts: [{ dice: 1d6 }]
285
+ - id: attribute
286
+ kind: choice
287
+ when: steps.roll.total == 5
288
+ options: { values: { formula: "keysOf('attr')" } }
289
+ recommend: >-
290
+ ['str', 'dex', 'con', 'int', 'wis', 'cha'][indexOf([attributes.str.score,
291
+ attributes.dex.score, attributes.con.score, attributes.int.score,
292
+ attributes.wis.score, attributes.cha.score], maxList([attributes.str.score,
293
+ attributes.dex.score, attributes.con.score, attributes.int.score,
294
+ attributes.wis.score, attributes.cha.score], x))]
295
+ - id: apply
296
+ kind: changes
297
+ changes:
298
+ - { type: adjust, field: effort.torched, by: 1 }
299
+ - { type: adjust, field: attributes.wis.score, by: -1, when: steps.roll.total <= 2 }
300
+ - type: adjust
301
+ when: steps.roll.total == 3 || steps.roll.total == 4
302
+ field: attributes.con.score
303
+ by: -1
304
+ - type: adjust
305
+ when: has(steps.attribute)
306
+ field: { formula: "'attributes.' + steps.attribute.picked + '.score'" }
307
+ by: -1
308
+ - id: result
309
+ kind: outcome
310
+ result: >-
311
+ steps.roll.total <= 2 ? 'wisdom' : steps.roll.total <= 4 ? 'constitution'
312
+ : 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 }