@robsonbittencourt/calc 0.10.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 (144) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc +12 -0
  3. package/bundle +107 -0
  4. package/dist/adaptable.d.ts +6 -0
  5. package/dist/adaptable.js +28 -0
  6. package/dist/adaptable.js.map +1 -0
  7. package/dist/calc.d.ts +6 -0
  8. package/dist/calc.js +26 -0
  9. package/dist/calc.js.map +1 -0
  10. package/dist/data/abilities.d.ts +15 -0
  11. package/dist/data/abilities.js +448 -0
  12. package/dist/data/abilities.js.map +1 -0
  13. package/dist/data/index.d.ts +2 -0
  14. package/dist/data/index.js +30 -0
  15. package/dist/data/index.js.map +1 -0
  16. package/dist/data/interface.d.ts +150 -0
  17. package/dist/data/interface.js +3 -0
  18. package/dist/data/interface.js.map +1 -0
  19. package/dist/data/items.d.ts +24 -0
  20. package/dist/data/items.js +708 -0
  21. package/dist/data/items.js.map +1 -0
  22. package/dist/data/moves.d.ts +86 -0
  23. package/dist/data/moves.js +5014 -0
  24. package/dist/data/moves.js.map +1 -0
  25. package/dist/data/natures.d.ts +17 -0
  26. package/dist/data/natures.js +127 -0
  27. package/dist/data/natures.js.map +1 -0
  28. package/dist/data/production.min.js +1 -0
  29. package/dist/data/species.d.ts +48 -0
  30. package/dist/data/species.js +10126 -0
  31. package/dist/data/species.js.map +1 -0
  32. package/dist/data/types.d.ts +23 -0
  33. package/dist/data/types.js +538 -0
  34. package/dist/data/types.js.map +1 -0
  35. package/dist/desc.d.ts +65 -0
  36. package/dist/desc.js +866 -0
  37. package/dist/desc.js.map +1 -0
  38. package/dist/field.d.ts +49 -0
  39. package/dist/field.js +111 -0
  40. package/dist/field.js.map +1 -0
  41. package/dist/index.d.ts +44 -0
  42. package/dist/index.js +99 -0
  43. package/dist/index.js.map +1 -0
  44. package/dist/items.d.ts +13 -0
  45. package/dist/items.js +434 -0
  46. package/dist/items.js.map +1 -0
  47. package/dist/mechanics/gen12.d.ts +6 -0
  48. package/dist/mechanics/gen12.js +271 -0
  49. package/dist/mechanics/gen12.js.map +1 -0
  50. package/dist/mechanics/gen3.d.ts +11 -0
  51. package/dist/mechanics/gen3.js +371 -0
  52. package/dist/mechanics/gen3.js.map +1 -0
  53. package/dist/mechanics/gen4.d.ts +11 -0
  54. package/dist/mechanics/gen4.js +596 -0
  55. package/dist/mechanics/gen4.js.map +1 -0
  56. package/dist/mechanics/gen56.d.ts +13 -0
  57. package/dist/mechanics/gen56.js +836 -0
  58. package/dist/mechanics/gen56.js.map +1 -0
  59. package/dist/mechanics/gen789.d.ts +14 -0
  60. package/dist/mechanics/gen789.js +1325 -0
  61. package/dist/mechanics/gen789.js.map +1 -0
  62. package/dist/mechanics/util.d.ts +39 -0
  63. package/dist/mechanics/util.js +675 -0
  64. package/dist/mechanics/util.js.map +1 -0
  65. package/dist/move.d.ts +50 -0
  66. package/dist/move.js +324 -0
  67. package/dist/move.js.map +1 -0
  68. package/dist/pokemon.d.ts +55 -0
  69. package/dist/pokemon.js +240 -0
  70. package/dist/pokemon.js.map +1 -0
  71. package/dist/production.min.js +1 -0
  72. package/dist/result.d.ts +34 -0
  73. package/dist/result.js +94 -0
  74. package/dist/result.js.map +1 -0
  75. package/dist/state.d.ts +77 -0
  76. package/dist/state.js +3 -0
  77. package/dist/state.js.map +1 -0
  78. package/dist/stats.d.ts +26 -0
  79. package/dist/stats.js +183 -0
  80. package/dist/stats.js.map +1 -0
  81. package/dist/test/calc.test.d.ts +1 -0
  82. package/dist/test/calc.test.js +1297 -0
  83. package/dist/test/calc.test.js.map +1 -0
  84. package/dist/test/data.test.d.ts +1 -0
  85. package/dist/test/data.test.js +368 -0
  86. package/dist/test/data.test.js.map +1 -0
  87. package/dist/test/gen.d.ts +135 -0
  88. package/dist/test/gen.js +636 -0
  89. package/dist/test/gen.js.map +1 -0
  90. package/dist/test/helper.d.ts +55 -0
  91. package/dist/test/helper.js +174 -0
  92. package/dist/test/helper.js.map +1 -0
  93. package/dist/test/move.test.d.ts +1 -0
  94. package/dist/test/move.test.js +14 -0
  95. package/dist/test/move.test.js.map +1 -0
  96. package/dist/test/pokemon.test.d.ts +1 -0
  97. package/dist/test/pokemon.test.js +102 -0
  98. package/dist/test/pokemon.test.js.map +1 -0
  99. package/dist/test/stats.test.d.ts +1 -0
  100. package/dist/test/stats.test.js +64 -0
  101. package/dist/test/stats.test.js.map +1 -0
  102. package/dist/test/utils.test.d.ts +1 -0
  103. package/dist/test/utils.test.js +19 -0
  104. package/dist/test/utils.test.js.map +1 -0
  105. package/dist/util.d.ts +17 -0
  106. package/dist/util.js +115 -0
  107. package/dist/util.js.map +1 -0
  108. package/jest.config.js +11 -0
  109. package/package.json +40 -0
  110. package/src/adaptable.ts +12 -0
  111. package/src/calc.ts +40 -0
  112. package/src/data/abilities.ts +383 -0
  113. package/src/data/index.ts +36 -0
  114. package/src/data/interface.ts +176 -0
  115. package/src/data/items.ts +632 -0
  116. package/src/data/moves.ts +5028 -0
  117. package/src/data/natures.ts +65 -0
  118. package/src/data/species.ts +10098 -0
  119. package/src/data/types.ts +478 -0
  120. package/src/desc.ts +1063 -0
  121. package/src/field.ts +124 -0
  122. package/src/index.ts +156 -0
  123. package/src/items.ts +423 -0
  124. package/src/mechanics/gen12.ts +297 -0
  125. package/src/mechanics/gen3.ts +444 -0
  126. package/src/mechanics/gen4.ts +702 -0
  127. package/src/mechanics/gen56.ts +1134 -0
  128. package/src/mechanics/gen789.ts +1788 -0
  129. package/src/mechanics/util.ts +676 -0
  130. package/src/move.ts +337 -0
  131. package/src/pokemon.ts +244 -0
  132. package/src/result.ts +106 -0
  133. package/src/state.ts +81 -0
  134. package/src/stats.ts +213 -0
  135. package/src/test/calc.test.ts +1588 -0
  136. package/src/test/data.test.ts +129 -0
  137. package/src/test/gen.ts +514 -0
  138. package/src/test/helper.ts +185 -0
  139. package/src/test/move.test.ts +13 -0
  140. package/src/test/pokemon.test.ts +121 -0
  141. package/src/test/stats.test.ts +84 -0
  142. package/src/test/utils.test.ts +18 -0
  143. package/src/util.ts +153 -0
  144. package/tsconfig.json +10 -0
@@ -0,0 +1,185 @@
1
+ /* eslint-env jest */
2
+
3
+ import type * as I from '../data/interface';
4
+ import {type Result, calculate, Pokemon, Move} from '../index';
5
+ import type {State} from '../state';
6
+ import {Field, Side} from '../field';
7
+
8
+ const calc = (gen: I.GenerationNum) => (
9
+ attacker: Pokemon,
10
+ defender: Pokemon,
11
+ move: Move,
12
+ field?: Field
13
+ ) => calculate(gen, attacker, defender, move, field);
14
+
15
+ const move = (gen: I.GenerationNum) => (
16
+ name: string,
17
+ options: Partial<Omit<State.Move, 'ability' | 'item' | 'species'>> & {
18
+ ability?: string;
19
+ item?: string;
20
+ species?: string;
21
+ } = {}
22
+ ) => new Move(gen, name, options as any);
23
+
24
+ const pokemon = (gen: I.GenerationNum) => (
25
+ name: string,
26
+ options: Partial<Omit<State.Pokemon, 'ability' | 'item' | 'nature' | 'moves'>> & {
27
+ ability?: string;
28
+ item?: string;
29
+ nature?: string;
30
+ moves?: string[];
31
+ curHP?: number;
32
+ ivs?: Partial<I.StatsTable> & {spc?: number};
33
+ evs?: Partial<I.StatsTable> & {spc?: number};
34
+ boosts?: Partial<I.StatsTable> & {spc?: number};
35
+ } = {}
36
+ ) => new Pokemon(gen, name, options as any);
37
+
38
+ const field = (field: Partial<State.Field> = {}) => new Field(field);
39
+
40
+ const side = (side: State.Side = {}) => new Side(side);
41
+
42
+ interface Gen {
43
+ gen: I.GenerationNum;
44
+ calculate: ReturnType<typeof calc>;
45
+ Pokemon: ReturnType<typeof pokemon>;
46
+ Move: ReturnType<typeof move>;
47
+ Field: typeof field;
48
+ Side: typeof side;
49
+ }
50
+
51
+ export function inGen(gen: I.GenerationNum, fn: (gen: Gen) => void) {
52
+ fn({
53
+ gen,
54
+ calculate: calc(gen),
55
+ Move: move(gen),
56
+ Pokemon: pokemon(gen),
57
+ Field: field,
58
+ Side: side,
59
+ });
60
+ }
61
+
62
+ export function inGens(from: I.GenerationNum, to: I.GenerationNum, fn: (gen: Gen) => void) {
63
+ for (let gen = from; gen <= to; gen++) {
64
+ inGen(gen, fn);
65
+ }
66
+ }
67
+
68
+ export function tests(name: string, fn: (gen: Gen) => void, type?: 'skip' | 'only'): void;
69
+ export function tests(
70
+ name: string,
71
+ from: I.GenerationNum,
72
+ fn: (gen: Gen) => void,
73
+ type?: 'skip' | 'only'
74
+ ): void;
75
+ export function tests(
76
+ name: string,
77
+ from: I.GenerationNum,
78
+ to: I.GenerationNum,
79
+ fn: (gen: Gen) => void,
80
+ type?: 'skip' | 'only'
81
+ ): void;
82
+ export function tests(...args: any[]) {
83
+ const name = args[0];
84
+ let from: I.GenerationNum;
85
+ let to: I.GenerationNum;
86
+ let fn: (gen: Gen) => void;
87
+ let type: 'skip' | 'only' | undefined = undefined;
88
+ if (typeof args[1] !== 'number') {
89
+ from = 1;
90
+ to = 9;
91
+ fn = args[1];
92
+ type = args[2];
93
+ } else if (typeof args[2] !== 'number') {
94
+ from = args[1] as I.GenerationNum ?? 1;
95
+ to = 9;
96
+ fn = args[2];
97
+ type = args[3];
98
+ } else {
99
+ from = args[1] as I.GenerationNum ?? 1;
100
+ to = args[2] as I.GenerationNum ?? 8;
101
+ fn = args[3];
102
+ type = args[4];
103
+ }
104
+
105
+ inGens(from, to, gen => {
106
+ const n = `${name} (gen ${gen.gen})`;
107
+ if (type === 'skip') {
108
+ test.skip(n, () => fn!(gen));
109
+ } else if (type === 'only') {
110
+ test.only(n, () => fn!(gen));
111
+ } else {
112
+ test(n, () => fn!(gen));
113
+ }
114
+ });
115
+ }
116
+
117
+ declare global {
118
+ namespace jest {
119
+ interface Matchers<R, T> {
120
+ toMatch(gen: I.GenerationNum, notation?: '%' | 'px' | ResultDiff, diff?: ResultDiff): R;
121
+ }
122
+ }
123
+ }
124
+
125
+ type ResultDiff = Partial<Record<I.GenerationNum, Partial<ResultBreakdown>>>;
126
+ interface ResultBreakdown {
127
+ range: [number, number];
128
+ desc: string;
129
+ result: string;
130
+ }
131
+
132
+ expect.extend({
133
+ toMatch(
134
+ received: Result,
135
+ gen: I.GenerationNum,
136
+ notation?: '%' | 'px' | ResultDiff,
137
+ diff?: ResultDiff
138
+ ) {
139
+ if (typeof notation !== 'string') {
140
+ diff = notation;
141
+ notation = '%';
142
+ }
143
+ if (!diff) throw new Error('toMatch called with no diff!');
144
+
145
+ const breakdowns = Object.entries(diff).sort() as [string, ResultBreakdown][];
146
+ const expected = {range: undefined! as [number, number], desc: '', result: ''};
147
+ for (const [g, {range, desc, result}] of breakdowns) {
148
+ if (Number(g) > gen) break;
149
+ if (range) expected.range = range;
150
+ if (desc) expected.desc = desc;
151
+ if (result) expected.result = result;
152
+ }
153
+
154
+ if (!(expected.range || expected.desc || expected.result)) {
155
+ throw new Error(`toMatch called with empty diff: ${diff}`);
156
+ }
157
+
158
+ if (expected.range) {
159
+ if (this.isNot) {
160
+ expect(received.range()).not.toEqual(expected.range);
161
+ } else {
162
+ expect(received.range()).toEqual(expected.range);
163
+ }
164
+ }
165
+ if (expected.desc) {
166
+ const r = received.fullDesc(notation).split(': ')[0];
167
+ if (this.isNot) {
168
+ expect(r).not.toEqual(expected.desc);
169
+ } else {
170
+ expect(r).toEqual(expected.desc);
171
+ }
172
+ }
173
+ if (expected.result) {
174
+ const post = received.fullDesc(notation).split(': ')[1];
175
+ const r = `(${post.split('(')[1]}`;
176
+ if (this.isNot) {
177
+ expect(r).not.toEqual(expected.result);
178
+ } else {
179
+ expect(r).toEqual(expected.result);
180
+ }
181
+ }
182
+
183
+ return {pass: !this.isNot, message: () => ''};
184
+ },
185
+ });
@@ -0,0 +1,13 @@
1
+ import {Move} from '../index';
2
+
3
+ describe('Move', () => {
4
+ test('clone', () => {
5
+ const m = new Move(7, 'Blizzard', {useZ: true});
6
+ expect(m.name).toBe('Subzero Slammer');
7
+ expect(m.bp).toBe(185);
8
+
9
+ const clone = m.clone();
10
+ expect(clone.name).toBe('Subzero Slammer');
11
+ expect(clone.bp).toBe(185);
12
+ });
13
+ });
@@ -0,0 +1,121 @@
1
+ import {Pokemon} from '../index';
2
+ import type {StatID, MoveName} from '../data/interface';
3
+
4
+ describe('Pokemon', () => {
5
+ test('defaults', () => {
6
+ const p = new Pokemon(7, 'Gengar');
7
+
8
+ expect(p.name).toBe('Gengar');
9
+ expect(p.types).toEqual(['Ghost', 'Poison']);
10
+ expect(p.weightkg).toBe(40.5);
11
+ expect(p.level).toBe(100);
12
+ expect(p.gender).toBe('M');
13
+ expect(p.item).toBeUndefined();
14
+ expect(p.ability).toBe('Cursed Body');
15
+ expect(p.nature).toBe('Serious');
16
+ expect(p.status).toBe('');
17
+ expect(p.hasStatus()).toBe(false);
18
+ expect(p.toxicCounter).toBe(0);
19
+ expect(p.curHP()).toBe(p.stats.hp);
20
+
21
+ let stat: StatID;
22
+ // tslint:disable-next-line:forin
23
+ for (stat in p.ivs) {
24
+ expect(p.ivs[stat]).toBe(31);
25
+ expect(p.evs[stat]).toBe(0);
26
+ expect(p.boosts[stat]).toBe(0);
27
+ }
28
+
29
+ expect(p.stats).toEqual({hp: 261, atk: 166, def: 156, spa: 296, spd: 186, spe: 256});
30
+ });
31
+
32
+ test('Pokemon full', () => {
33
+ const p = new Pokemon(7, 'Suicune', {
34
+ level: 50,
35
+ ability: 'Inner Focus',
36
+ item: 'Leftovers',
37
+ nature: 'Bold',
38
+ ivs: {spa: 30},
39
+ evs: {spd: 4, def: 252, hp: 252},
40
+ boosts: {atk: -1, spa: 2, spd: 1},
41
+ curHP: 60,
42
+ status: 'tox',
43
+ toxicCounter: 2,
44
+ moves: ['Surf', 'Rest', 'Curse', 'Sleep Talk'],
45
+ });
46
+
47
+ expect(p.name).toBe('Suicune');
48
+ expect(p.types).toEqual(['Water']);
49
+ expect(p.weightkg).toBe(187.0);
50
+ expect(p.level).toBe(50);
51
+ expect(p.gender).toBe('N');
52
+ expect(p.item).toBe('Leftovers');
53
+ expect(p.ability).toBe('Inner Focus');
54
+ expect(p.nature).toBe('Bold');
55
+ expect(p.status).toBe('tox');
56
+ expect(p.toxicCounter).toBe(2);
57
+ expect(p.curHP()).toBe(60);
58
+
59
+ expect(p.ivs).toEqual({hp: 31, atk: 31, def: 31, spa: 30, spd: 31, spe: 31});
60
+ expect(p.evs).toEqual({hp: 252, atk: 0, def: 252, spa: 0, spd: 4, spe: 0});
61
+ expect(p.boosts).toEqual({hp: 0, atk: -1, def: 0, spa: 2, spd: 1, spe: 0});
62
+ expect(p.stats).toEqual({hp: 207, atk: 85, def: 183, spa: 110, spd: 136, spe: 105});
63
+
64
+ expect(p.moves).toEqual(['Surf', 'Rest', 'Curse', 'Sleep Talk'] as MoveName[]);
65
+ });
66
+
67
+ test('gen1', () => {
68
+ const p = new Pokemon(1, 'Tauros', {
69
+ level: 100,
70
+ ivs: {spc: 20, def: 16},
71
+ evs: {atk: 200},
72
+ curHP: 500,
73
+ });
74
+
75
+ // HP DV should be derived
76
+ expect(p.ivs).toEqual({hp: 20, atk: 31, def: 16, spa: 20, spd: 20, spe: 31});
77
+ expect(p.evs).toEqual({hp: 252, atk: 200, def: 252, spa: 252, spd: 252, spe: 252});
78
+ expect(p.stats).toEqual({hp: 343, atk: 298, def: 274, spa: 228, spd: 228, spe: 318});
79
+
80
+ // curHP() capped to maxHP
81
+ expect(p.curHP()).toBe(p.maxHP());
82
+ });
83
+
84
+ test('getForme', () => {
85
+ expect(Pokemon.getForme(1, 'Gengar')).toBe('Gengar');
86
+
87
+ expect(Pokemon.getForme(7, 'Gengar', 'Black Sludge', 'Hypnosis')).toBe('Gengar');
88
+ expect(Pokemon.getForme(7, 'Gengar', 'Gengarite', 'Hypnosis')).toBe('Gengar-Mega');
89
+
90
+ expect(Pokemon.getForme(7, 'Charizard')).toBe('Charizard');
91
+ expect(Pokemon.getForme(7, 'Charizard', 'Charizardite X')).toBe('Charizard-Mega-X');
92
+ expect(Pokemon.getForme(7, 'Charizard', 'Charizardite Y')).toBe('Charizard-Mega-Y');
93
+ expect(Pokemon.getForme(7, 'Mewtwo', 'Choice Specs', 'Psystrike')).toBe('Mewtwo');
94
+ expect(Pokemon.getForme(7, 'Mewtwo', 'Mewtwonite X', 'Psystrike')).toBe('Mewtwo-Mega-X');
95
+ expect(Pokemon.getForme(7, 'Mewtwo', 'Mewtwonite Y', 'Psystrike')).toBe('Mewtwo-Mega-Y');
96
+
97
+ expect(Pokemon.getForme(7, 'Groudon', 'Choice Band', 'Earthquake')).toBe('Groudon');
98
+ expect(Pokemon.getForme(7, 'Groudon', 'Red Orb', 'Earthquake')).toBe('Groudon-Primal');
99
+ expect(Pokemon.getForme(7, 'Kyogre', 'Choice Specs', 'Surf')).toBe('Kyogre');
100
+ expect(Pokemon.getForme(7, 'Kyogre', 'Blue Orb', 'Surf')).toBe('Kyogre-Primal');
101
+
102
+ expect(Pokemon.getForme(7, 'Meloetta', 'Leftovers', 'Psychic')).toBe('Meloetta');
103
+ expect(Pokemon.getForme(7, 'Meloetta', 'Leftovers', 'Relic Song')).toBe('Meloetta-Pirouette');
104
+ expect(Pokemon.getForme(7, 'Rayquaza', undefined, 'Earthquake')).toBe('Rayquaza');
105
+ expect(Pokemon.getForme(7, 'Rayquaza', undefined, 'Dragon Ascent')).toBe('Rayquaza-Mega');
106
+ });
107
+
108
+ test('hasType', () => {
109
+ const p = new Pokemon(7, 'Gengar');
110
+ expect(p.hasType('Ghost')).toBe(true);
111
+ expect(p.hasType('Poison')).toBe(true);
112
+ expect(p.hasType('Fire')).toBe(false);
113
+ expect(p.hasType('Ice')).toBe(false);
114
+ });
115
+
116
+ test('Gigantamx weights', () => {
117
+ expect(new Pokemon(8, 'Venusaur-Gmax').weightkg).toBe(100);
118
+ expect(new Pokemon(8, 'Venusaur-Gmax', {isDynamaxed: true}).weightkg).toBe(0);
119
+ expect(new Pokemon(8, 'Venusaur-Gmax', {overrides: {weightkg: 50}}).weightkg).toBe(50);
120
+ });
121
+ });
@@ -0,0 +1,84 @@
1
+ import {Generations} from '../data';
2
+ import type {GenerationNum, StatsTable, StatID} from '../data/interface';
3
+ import {Stats} from '../stats';
4
+ import {getModifiedStat} from '../mechanics/util';
5
+
6
+ describe('Stats', () => {
7
+ test('displayStat', () => {
8
+ expect(Stats.displayStat('hp')).toBe('HP');
9
+ expect(Stats.displayStat('atk')).toBe('Atk');
10
+ expect(Stats.displayStat('def')).toBe('Def');
11
+ expect(Stats.displayStat('spa')).toBe('SpA');
12
+ expect(Stats.displayStat('spd')).toBe('SpD');
13
+ expect(Stats.displayStat('spe')).toBe('Spe');
14
+ expect(Stats.displayStat('spc')).toBe('Spc');
15
+ });
16
+
17
+ test('calcStat', () => {
18
+ const RBY: StatsTable = {
19
+ hp: 403,
20
+ atk: 298,
21
+ def: 298,
22
+ spa: 298,
23
+ spd: 298,
24
+ spe: 298,
25
+ };
26
+ const ADV: StatsTable = {hp: 404, atk: 328, def: 299, spa: 269, spd: 299, spe: 299};
27
+ for (let gen = 1; gen <= 9; gen++) {
28
+ for (const s in ADV) {
29
+ const stat = s as StatID;
30
+ const val = Stats.calcStat(
31
+ Generations.get(gen as GenerationNum),
32
+ stat,
33
+ 100,
34
+ 31,
35
+ 252,
36
+ 100,
37
+ 'Adamant'
38
+ );
39
+ expect(val).toBe(gen < 3 ? RBY[stat] : ADV[stat]);
40
+ }
41
+ }
42
+
43
+ // Shedinja
44
+ expect(Stats.calcStat(Generations.get(8), 'hp', 1, 31, 252, 100, 'Jolly')).toBe(1);
45
+ // no nature
46
+ expect(Stats.calcStat(Generations.get(8), 'atk', 100, 31, 252, 100)).toBe(299);
47
+ });
48
+
49
+ test('dvs', () => {
50
+ for (let dv = 0; dv <= 15; dv++) {
51
+ expect(Stats.IVToDV(Stats.DVToIV(dv))).toBe(dv);
52
+ }
53
+
54
+ expect(
55
+ Stats.getHPDV({
56
+ atk: Stats.DVToIV(15),
57
+ def: Stats.DVToIV(15),
58
+ spc: Stats.DVToIV(15),
59
+ spe: Stats.DVToIV(15),
60
+ })
61
+ ).toBe(15);
62
+ expect(
63
+ Stats.getHPDV({
64
+ atk: Stats.DVToIV(5),
65
+ def: Stats.DVToIV(15),
66
+ spc: Stats.DVToIV(13),
67
+ spe: Stats.DVToIV(13),
68
+ })
69
+ ).toBe(15);
70
+ expect(
71
+ Stats.getHPDV({
72
+ atk: Stats.DVToIV(15),
73
+ def: Stats.DVToIV(3),
74
+ spc: Stats.DVToIV(11),
75
+ spe: Stats.DVToIV(10),
76
+ })
77
+ ).toBe(13);
78
+ });
79
+
80
+ test('gen 2 modifications', () => {
81
+ expect(getModifiedStat(158, -1, Generations.get(2))).toBe(104); // Snorlax after Curse
82
+ expect(getModifiedStat(238, -1, Generations.get(2))).toBe(157); // Skarmory after Curse
83
+ });
84
+ });
@@ -0,0 +1,18 @@
1
+ import {extend} from '../util';
2
+
3
+ describe('util', () => {
4
+ test('extend', () => {
5
+ const obj1 = {a: 1, b: {c: 2}, d: {e: 3}, f: 4};
6
+ const obj2 = {a: 2, b: {c: 3}, d: 4, e: {f: 5}};
7
+
8
+ expect(extend(true, {}, obj1)).toEqual(obj1);
9
+ expect(extend(true, {}, obj1, obj2)).toEqual({a: 2, b: {c: 3}, d: 4, e: {f: 5}, f: 4});
10
+ expect(extend(true, {}, obj2, obj1)).toEqual({
11
+ a: 1,
12
+ b: {c: 2},
13
+ d: {e: 3},
14
+ e: {f: 5},
15
+ f: 4,
16
+ });
17
+ });
18
+ });
package/src/util.ts ADDED
@@ -0,0 +1,153 @@
1
+ /* eslint-disable eqeqeq, @typescript-eslint/unbound-method, @typescript-eslint/ban-types */
2
+ import type {ID} from './data/interface';
3
+
4
+ export function toID(text: any): ID {
5
+ return ('' + text).toLowerCase().replace(/[^a-z0-9]+/g, '') as ID;
6
+ }
7
+
8
+ export function error(err: boolean, msg: string) {
9
+ if (err) {
10
+ throw new Error(msg);
11
+ } else {
12
+ console.log(msg);
13
+ }
14
+ }
15
+
16
+ export function assignWithout(
17
+ a: {[key: string]: any}, b: {[key: string]: any}, exclude: Set<string>
18
+ ) {
19
+ for (const key in b) {
20
+ if (Object.prototype.hasOwnProperty.call(b, key) && !exclude.has(key)) {
21
+ a[key] = b[key];
22
+ }
23
+ }
24
+ }
25
+
26
+ // https://github.com/krzkaczor/ts-essentials v6.0.5
27
+ // MIT License Copyright 2018-2019 Chris Kaczor
28
+ export type Primitive = string | number | boolean | bigint | symbol | undefined | null;
29
+ export type Builtin = Primitive | Function | Date | Error | RegExp;
30
+
31
+ export type IsTuple<T> =
32
+ T extends [infer A] ? T
33
+ : T extends [infer A, infer B] ? T
34
+ : T extends [infer A, infer B, infer C] ? T
35
+ : T extends [infer A, infer B, infer C, infer D] ? T
36
+ : T extends [infer A, infer B, infer C, infer D, infer E] ? T
37
+ : never;
38
+
39
+ export type DeepPartial<T> =
40
+ T extends Builtin ? T
41
+ : T extends Map<infer K, infer V> ? Map<DeepPartial<K>, DeepPartial<V>>
42
+ : T extends ReadonlyMap<infer K, infer V> ? ReadonlyMap<DeepPartial<K>, DeepPartial<V>>
43
+ : T extends Set<infer U> ? Set<DeepPartial<U>>
44
+ : T extends ReadonlySet<infer U> ? ReadonlySet<DeepPartial<U>>
45
+ : T extends Array<infer U> ? T extends IsTuple<T>
46
+ ? { [K in keyof T]?: DeepPartial<T[K]> }
47
+ : Array<DeepPartial<U>>
48
+ : T extends Promise<infer U> ? Promise<DeepPartial<U>>
49
+ : T extends {} ? { [K in keyof T]?: DeepPartial<T[K]> }
50
+ : Partial<T>;
51
+
52
+ // jQuery JavaScript Library v2.0.3
53
+ // Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors
54
+ const class2Type: {[c: string]: string} = {
55
+ '[object Boolean]': 'boolean',
56
+ '[object Number]': 'number',
57
+ '[object String]': 'string',
58
+ '[object Function]': 'function',
59
+ '[object Array]': 'array',
60
+ '[object Date]': 'date',
61
+ '[object RegExp]': 'regexp',
62
+ '[object Object]': 'object',
63
+ '[object Error]': 'error',
64
+ };
65
+
66
+ const coreToString = class2Type.toString;
67
+ const coreHasOwn = class2Type.hasOwnProperty;
68
+
69
+ function isFunction(obj: any) {
70
+ return getType(obj) === 'function';
71
+ }
72
+
73
+ function isWindow(obj: any) {
74
+ return obj != null && obj === obj.window;
75
+ }
76
+
77
+ function getType(obj: any) {
78
+ if (obj == null) {
79
+ return String(obj);
80
+ }
81
+ return typeof obj === 'object' || typeof obj === 'function'
82
+ ? class2Type[coreToString.call(obj)] || 'object'
83
+ : typeof obj;
84
+ }
85
+
86
+ function isPlainObject(obj: any) {
87
+ if (getType(obj) !== 'object' || obj.nodeType || isWindow(obj)) {
88
+ return false;
89
+ }
90
+
91
+ try {
92
+ if (obj.constructor && !coreHasOwn.call(obj.constructor.prototype, 'isPrototypeOf')) {
93
+ return false;
94
+ }
95
+ } catch (e) {
96
+ return false;
97
+ }
98
+
99
+ return true;
100
+ }
101
+
102
+ export function extend(this: any, ...args: any[]) {
103
+ let options, name, src, copy, copyIsArray, clone;
104
+ let target = args[0] || {};
105
+ let i = 1;
106
+ let deep = false;
107
+ const length = args.length;
108
+
109
+ if (typeof target === 'boolean') {
110
+ deep = target;
111
+ target = args[1] || {};
112
+ i = 2;
113
+ }
114
+
115
+ if (typeof target !== 'object' && !isFunction(target)) {
116
+ target = {};
117
+ }
118
+
119
+ if (length === i) {
120
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
121
+ target = this;
122
+ --i;
123
+ }
124
+
125
+ for (; i < length; i++) {
126
+ if ((options = args[i]) != null) {
127
+ // tslint:disable-next-line: forin
128
+ for (name in options) {
129
+ src = target[name];
130
+ copy = options[name];
131
+
132
+ if (target === copy) {
133
+ continue;
134
+ }
135
+
136
+ if (deep && copy && (isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) {
137
+ if (copyIsArray) {
138
+ copyIsArray = false;
139
+ clone = src && Array.isArray(src) ? src : [];
140
+ } else {
141
+ clone = src && isPlainObject(src) ? src : {};
142
+ }
143
+
144
+ target[name] = extend(deep, clone, copy);
145
+ } else if (copy !== undefined) {
146
+ target[name] = copy;
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ return target;
153
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../tsconfig.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src",
5
+ "outDir": "dist",
6
+ "downlevelIteration": true,
7
+ "tsBuildInfoFile": ".tsbuildinfo"
8
+ },
9
+ "exclude": ["dist"]
10
+ }