this repo has no description
1import { DevVielleDndPower } from "../lexicons";
2
3export const powers = {
4 ELDRITCHADAPTABILITY: DevVielleDndPower.eldritchAdaptabilitySchema.expected,
5 ELDRITCHASSAULT: DevVielleDndPower.eldritchAssaultSchema.expected,
6 RUNESEEKER: DevVielleDndPower.runeSeekerSchema.expected,
7 FATESCRIBER: DevVielleDndPower.fateScriberSchema.expected,
8 FACELESS: DevVielleDndPower.facelessSchema.expected,
9 BIND: DevVielleDndPower.bindSchema.expected,
10 SPRAY: DevVielleDndPower.spraySchema.expected,
11 ACURSED: DevVielleDndPower.acursedSchema.expected,
12 DARKSIGHT: DevVielleDndPower.darksightSchema.expected,
13 ELDRITCHVISAGE: DevVielleDndPower.eldritchVisageSchema.expected,
14 REGENERATE: DevVielleDndPower.regenerateSchema.expected,
15 INSTIL: DevVielleDndPower.instilSchema.expected,
16 ELDRITCHENCHANTMENT: DevVielleDndPower.eldritchEnchantmentSchema.expected,
17 WHISPER: DevVielleDndPower.whisperSchema.expected,
18 BOND: DevVielleDndPower.bondSchema.expected,
19 CLAW: DevVielleDndPower.clawSchema.expected,
20 INVALID: DevVielleDndPower.invalidSchema.expected,
21 LOCKED: DevVielleDndPower.lockedSchema.expected,
22} as const;
23
24export const normalPowers = [
25 powers.ELDRITCHADAPTABILITY,
26 powers.ELDRITCHASSAULT,
27 powers.RUNESEEKER,
28 powers.FATESCRIBER,
29 powers.FACELESS,
30 powers.BIND,
31 powers.SPRAY,
32 powers.ACURSED,
33 powers.DARKSIGHT,
34 powers.ELDRITCHVISAGE,
35 powers.REGENERATE,
36 powers.INSTIL,
37 powers.ELDRITCHENCHANTMENT,
38 powers.WHISPER,
39 powers.BOND,
40 powers.CLAW,
41] as const;
42
43export type powerId = (typeof powers)[keyof typeof powers];
44export const isPowerId = (power: unknown): power is powerId =>
45 Object.values(powers).includes(power as powerId);
46
47export interface Power {
48 name: string;
49 forceSelect?: true;
50 description: string;
51 image: {
52 src: string;
53 alt: string;
54 };
55 meta: {
56 name: string;
57 value: string;
58 }[];
59}
60
61export const powerData: Record<powerId, Power> = {
62 [powers.ELDRITCHADAPTABILITY]: {
63 name: "Eldritch Adaptability",
64 forceSelect: true,
65 description:
66 "You become more adaptable to other envirmonents. When entering another world your body automatically adjusts to endure there better. This can include new languages, gills, cultural understanding, and more.",
67 image: {
68 src: "/astral/eldritch_adaptability.webp",
69 alt: "",
70 },
71 meta: [],
72 },
73 [powers.ELDRITCHASSAULT]: {
74 name: "Eldritch Assault",
75 description:
76 "Use your action to cause your attacks to deal an additional 1d4 Force damage for the next 10 turns, but you take 1d4 Force damage for the next 10 turns. To determine damage, roll 2 dice. Use the lower result for damage dealt to yourself, and the higher for the damage dealt to the target. This dice increases to a d6 at 5th level, d8 at 11th level, and d10 at 17th level. Additionally, you take 1 less damage from this at 7th level, 2 less at 15th level, and 3 less at 19th level. (This cannot reduce damage below 1.)",
77 image: {
78 src: "/astral/eldritch_assault.webp",
79 alt: "",
80 },
81 meta: [],
82 },
83 [powers.RUNESEEKER]: {
84 name: "Rune Seeker",
85 description:
86 "You may cast Comprehend Languages. This does not cost V, S, or M components. If you use all 3 uses you may cast it using spell slots as a normal spell.",
87 image: {
88 src: "/astral/rune_seeker.webp",
89 alt: "",
90 },
91 meta: [
92 {
93 name: "Charges",
94 value: "3x long rest",
95 },
96 ],
97 },
98 [powers.FATESCRIBER]: {
99 name: "Fate Scriber",
100 description:
101 "You may make an attack hit if it was a miss, a miss if it was a hit, a critical hit if it was a hit, or a normal hit if it was a critical hit. This costs a reaction and may be performed on any attack roll.",
102 image: {
103 src: "/astral/fate_scriber.webp",
104 alt: "",
105 },
106 meta: [
107 {
108 name: "Charges",
109 value: "1x long rest",
110 },
111 {
112 name: "Range",
113 value: "60ft",
114 },
115 ],
116 },
117 [powers.FACELESS]: {
118 name: "Faceless",
119 description:
120 "You may cast disguise self as an action without expending a spell slot. It takes an action to dispell the illusion created this way, and you must pass a DC10 sanity save or choose a different apperance instead of dropping the illusion.",
121 image: {
122 src: "/astral/faceless.webp",
123 alt: "",
124 },
125 meta: [],
126 },
127 [powers.BIND]: {
128 name: "Bind",
129 description:
130 "As an action, target 2 creatures you can see that are within 15ft of each other. The creatures must make a dex save (DC equals 9 + half your proficieny bonus + any ability modifier of your choosing) or they are tied together. If one creature passes the save, the other creature is dragged to the creature who saved, otherwise they are both moved to a tile between them. If either creature moves, the other creature moves with it and they stay in the same position relative to each other. They are both considered grappled, with the exception of the advantage/disadvantage, which is replaced to a +2 and -2 respectivley. This requires concentration and lasts up to 5 turns.",
131 image: {
132 src: "/astral/bind.webp",
133 alt: "",
134 },
135 meta: [
136 {
137 name: "Duration",
138 value: "30 seconds, concentration",
139 },
140 {
141 name: "Charges",
142 value: "prof bonus x per short rest",
143 },
144 {
145 name: "Range",
146 value: "120ft",
147 },
148 ],
149 },
150 [powers.SPRAY]: {
151 name: "Spray",
152 description:
153 "Choose one damaging cantrip you have access to which gains additional damage dice at 5th, 11th, and 17th level. The cantrip no longer gains aditional damage dice in this way, but can instead target 2 different creatures at level 5, 3 at level 11, and 4 at level 17. You must make an attack roll for each target. The effect can target the same creature multiple times.",
154 image: {
155 src: "/astral/spray.webp",
156 alt: "",
157 },
158 meta: [],
159 },
160 [powers.ACURSED]: {
161 name: "Acursed",
162 description:
163 "As an action, choose 1 creature. The creature takes 1d8 force damage whenever you attack it or deal damage (even if the attack misses or it saves). It takes an additional d8 of damage for every extra unique damage type in the attack (ie: 1d6 piercing gets 1d8, 1d6 piercing and 5d6 cold and 2d4 radiant and 1d8 piercing gets 3d8. The creature also gets disadvantage on any d20 test using an ability you choose when you select the creature. This can be cast while raging",
164 image: {
165 src: "/astral/acursed.webp",
166 alt: "",
167 },
168 meta: [
169 {
170 name: "Charges",
171 value: "1x short rest, concentration",
172 },
173 {
174 name: "Range",
175 value: "120ft",
176 },
177 ],
178 },
179 [powers.DARKSIGHT]: {
180 name: "Darksight",
181 description:
182 "You gain darkvision and can see through any magical darkness created by your spells or powers. You can allow any creature to see through darkness made by your spells at any point at no cost. If you already have darkvision of 120ft or greater, your darkvision increases by 120ft. This does not affect your ability to see through magical darkness.",
183 image: {
184 src: "/astral/darksight.webp",
185 alt: "",
186 },
187 meta: [
188 {
189 name: "Duration",
190 value: "passive",
191 },
192 {
193 name: "Range",
194 value: "120ft",
195 },
196 ],
197 },
198 [powers.ELDRITCHVISAGE]: {
199 name: "Eldritch Visage",
200 description:
201 "You gain Truesight for the next round. This requires concentration but do not gain the ability to see into the ethereal plane.",
202 image: {
203 src: "/astral/eldritch_visage.webp",
204 alt: "",
205 },
206 meta: [
207 {
208 name: "Charges",
209 value: "1x long rest",
210 },
211 {
212 name: "Range",
213 value: "15ft",
214 },
215 ],
216 },
217 [powers.REGENERATE]: {
218 name: "Regenerate",
219 description:
220 "As an action you may target yourself or someone else with access to Astral Powers. You choose an astral power they have access to which recharges on a short or long rest and has been used. The ability can be used. If it can be used multiple times it regains half its uses. If you do not know what abilities they have then an ability is choosen at random by the DM. This cannot be recharged using this same ability.",
221 image: {
222 src: "/astral/regenerate.webp",
223 alt: "",
224 },
225 meta: [
226 {
227 name: "Charges",
228 value: "1x long rest",
229 },
230 {
231 name: "Range",
232 value: "touch",
233 },
234 ],
235 },
236 [powers.INSTIL]: {
237 name: "Instill",
238 description:
239 "Use your action to allow a creature to take any one of their actions or bonus actions as a free action.",
240 image: {
241 src: "/astral/instill.webp",
242 alt: "",
243 },
244 meta: [
245 {
246 name: "Charges",
247 value: "proficiency x short rest",
248 },
249 {
250 name: "Range",
251 value: "120ft",
252 },
253 ],
254 },
255 [powers.ELDRITCHENCHANTMENT]: {
256 name: "Eldritch Enchantment",
257 description:
258 "You may cast Friends or Minor Illusion at will as an action. You may also cast Animal Friendship, Charm Person, or Illusiory Script.",
259 image: {
260 src: "/astral/eldritch_enchantment.webp",
261 alt: "",
262 },
263 meta: [
264 {
265 name: "Charges",
266 value: "prof bonus x per day (af, cp, is)",
267 },
268 ],
269 },
270 [powers.WHISPER]: {
271 name: "Whisperer",
272 description:
273 "Choose 3 charisma based skills or 2 charisma based skill and 3 musical instruments. You gain proficiency in those skills and instruments.",
274 image: {
275 src: "/astral/whisperer.webp",
276 alt: "",
277 },
278 meta: [
279 {
280 name: "Duration",
281 value: "passive",
282 },
283 ],
284 },
285 [powers.BOND]: {
286 name: "Bond",
287 description:
288 "You may bond to a willing creature once after gaining this power. This creature becomes your familiar and gains all the boons of find familiar and none of the drawbacks. This creature must be in the small pocket dimension while another creature from Find Familiar and other similar effects are in the world. The bonded creature cannot die and gains an ability score improvement when you reach levels 4, 8, 12, 16, 19, and 20. You do not gain ASIs retroactivley upon bonding. If you choose to bond to a familiar, the creature gains the additional boons listed and you may negotiate new powers, abilities, or improvements with your DM. If the creature you bond to chooses to end your bond, you loose this feature and gain one extra astral power point. Regaining this feature after loosing it allows you to choose a new creature. When a creature chooses to break its bond with you it will gain the ability to return to any point it knows in its home reality once, in order to leave.",
289 image: {
290 src: "/astral/bond.webp",
291 alt: "",
292 },
293 meta: [
294 {
295 name: "Charges",
296 value: "1x unlocked (bond), 1x short rest (revive)",
297 },
298 {
299 name: "Range",
300 value: "touch",
301 },
302 ],
303 },
304 [powers.CLAW]: {
305 name: "Claw",
306 description:
307 "Touch a severed hand which has similar atributes to a crawling claw. The hand becomes a crawling claw which you control for the duration. You can cast spells with a range of touch through it, and control it in ititiative. It takes its turn immediatley after yours, and casting a spell through it takes its action. After the duration of the power, the claw gains sentience and you loose control. It gains the consciencness if the owner of the original owner and can understand your words but not other peoples. You may only have one claw at a time. <br /> <b>Changes from statblock:</b> <br /> The claw shares an alignment with its original owner. It can understand any language, but only when spoken by the animator. The damage type from its attack is determined based on which would deal more damage to the target (accounting for immunity and resistance and bonus damage)",
308 image: {
309 src: "/astral/claw.webp",
310 alt: "",
311 },
312 meta: [
313 {
314 name: "Duration",
315 value: "24 hours",
316 },
317 {
318 name: "Charges",
319 value: "1x long rest",
320 },
321 ],
322 },
323 [powers.INVALID]: {
324 name: "Invalid Power",
325 description: "Illegal state",
326 image: {
327 src: "/astral/locked.webp",
328 alt: "Locked power",
329 },
330 meta: [],
331 },
332 [powers.LOCKED]: {
333 name: "Locked Power",
334 description: "Locked",
335 image: {
336 src: "/astral/locked.webp",
337 alt: "Locked power",
338 },
339 meta: [],
340 },
341};
342
343export const powerTree: { id: powerId; children: (typeof powerTree)[] } = {
344 id: powers.ELDRITCHADAPTABILITY,
345 children: [
346 {
347 id: powers.ELDRITCHASSAULT,
348 children: [
349 {
350 id: powers.SPRAY,
351 children: [
352 {
353 id: powers.LOCKED,
354 children: [
355 { id: powers.LOCKED, children: [] },
356 { id: powers.LOCKED, children: [] },
357 ],
358 },
359 ],
360 },
361 {
362 id: powers.ACURSED,
363 children: [
364 {
365 id: powers.LOCKED,
366 children: [
367 { id: powers.LOCKED, children: [] },
368 { id: powers.LOCKED, children: [] },
369 ],
370 },
371 ],
372 },
373 ],
374 },
375 {
376 id: powers.RUNESEEKER,
377 children: [
378 {
379 id: powers.DARKSIGHT,
380 children: [
381 {
382 id: powers.LOCKED,
383 children: [
384 { id: powers.LOCKED, children: [] },
385 { id: powers.LOCKED, children: [] },
386 ],
387 },
388 ],
389 },
390 {
391 id: powers.ELDRITCHVISAGE,
392 children: [
393 {
394 id: powers.LOCKED,
395 children: [
396 { id: powers.LOCKED, children: [] },
397 { id: powers.LOCKED, children: [] },
398 ],
399 },
400 ],
401 },
402 ],
403 },
404 {
405 id: powers.FATESCRIBER,
406 children: [
407 {
408 id: powers.REGENERATE,
409 children: [
410 {
411 id: powers.LOCKED,
412 children: [
413 { id: powers.LOCKED, children: [] },
414 { id: powers.LOCKED, children: [] },
415 ],
416 },
417 ],
418 },
419 {
420 id: powers.INSTIL,
421 children: [
422 {
423 id: powers.LOCKED,
424 children: [
425 { id: powers.LOCKED, children: [] },
426 { id: powers.LOCKED, children: [] },
427 ],
428 },
429 ],
430 },
431 ],
432 },
433 {
434 id: powers.FACELESS,
435 children: [
436 {
437 id: powers.ELDRITCHENCHANTMENT,
438 children: [
439 {
440 id: powers.LOCKED,
441 children: [
442 { id: powers.LOCKED, children: [] },
443 { id: powers.LOCKED, children: [] },
444 ],
445 },
446 ],
447 },
448 {
449 id: powers.WHISPER,
450 children: [
451 {
452 id: powers.LOCKED,
453 children: [
454 { id: powers.LOCKED, children: [] },
455 { id: powers.LOCKED, children: [] },
456 ],
457 },
458 ],
459 },
460 ],
461 },
462 {
463 id: powers.BIND,
464 children: [
465 {
466 id: powers.BOND,
467 children: [
468 {
469 id: powers.LOCKED,
470 children: [
471 { id: powers.LOCKED, children: [] },
472 { id: powers.LOCKED, children: [] },
473 ],
474 },
475 ],
476 },
477 {
478 id: powers.CLAW,
479 children: [
480 {
481 id: powers.LOCKED,
482 children: [
483 { id: powers.LOCKED, children: [] },
484 { id: powers.LOCKED, children: [] },
485 ],
486 },
487 ],
488 },
489 ],
490 },
491 ],
492} as const;
493
494type flatPower = { id: powerId; parents: powerId[] };
495
496const flatten = (power: typeof powerTree): flatPower[] =>
497 power.children.length === 0
498 ? [
499 {
500 id: power.id,
501 parents: [],
502 },
503 ]
504 : power.children
505 .map((x) => [...flatten(x), { id: power.id, parents: [] }])
506 .flat()
507 .map((x) => ({ id: x.id, parents: [power.id, ...x.parents] }));
508
509export const parentPowers = Object.fromEntries(
510 flatten(powerTree).map((x) => [x.id, x.parents]),
511);