volleyballsimtypes 0.0.514 → 0.0.516

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 (43) hide show
  1. package/dist/cjs/src/api/index.d.ts +1 -2
  2. package/dist/cjs/src/api/tactics-player-refs.js +2 -2
  3. package/dist/cjs/src/data/models/tactics.d.ts +2 -4
  4. package/dist/cjs/src/data/models/tactics.js +0 -5
  5. package/dist/cjs/src/data/transformers/tactics.js +4 -36
  6. package/dist/cjs/src/data/transformers/tactics.test.js +9 -46
  7. package/dist/cjs/src/service/team/attack-priority.d.ts +3 -0
  8. package/dist/cjs/src/service/team/attack-priority.js +11 -0
  9. package/dist/cjs/src/service/team/base-config.d.ts +2 -0
  10. package/dist/cjs/src/service/team/default-base-config.js +59 -3
  11. package/dist/cjs/src/service/team/default-base-config.test.d.ts +1 -0
  12. package/dist/cjs/src/service/team/default-base-config.test.js +44 -0
  13. package/dist/cjs/src/service/team/index.d.ts +1 -0
  14. package/dist/cjs/src/service/team/index.js +1 -0
  15. package/dist/cjs/src/service/team/offensive-preference.d.ts +2 -1
  16. package/dist/cjs/src/service/team/schemas/tactics.z.d.ts +19 -5
  17. package/dist/cjs/src/service/team/schemas/tactics.z.js +32 -33
  18. package/dist/cjs/src/service/team/schemas/tactics.z.test.js +25 -92
  19. package/dist/cjs/src/service/team/schemas/team.z.d.ts +19 -5
  20. package/dist/cjs/src/service/team/tactics.d.ts +0 -2
  21. package/dist/cjs/src/service/team/tactics.js +1 -2
  22. package/dist/esm/src/api/index.d.ts +1 -2
  23. package/dist/esm/src/api/tactics-player-refs.js +2 -2
  24. package/dist/esm/src/data/models/tactics.d.ts +2 -4
  25. package/dist/esm/src/data/models/tactics.js +0 -5
  26. package/dist/esm/src/data/transformers/tactics.js +4 -36
  27. package/dist/esm/src/data/transformers/tactics.test.js +9 -46
  28. package/dist/esm/src/service/team/attack-priority.d.ts +3 -0
  29. package/dist/esm/src/service/team/attack-priority.js +8 -0
  30. package/dist/esm/src/service/team/base-config.d.ts +2 -0
  31. package/dist/esm/src/service/team/default-base-config.js +59 -3
  32. package/dist/esm/src/service/team/default-base-config.test.d.ts +1 -0
  33. package/dist/esm/src/service/team/default-base-config.test.js +42 -0
  34. package/dist/esm/src/service/team/index.d.ts +1 -0
  35. package/dist/esm/src/service/team/index.js +1 -0
  36. package/dist/esm/src/service/team/offensive-preference.d.ts +2 -1
  37. package/dist/esm/src/service/team/schemas/tactics.z.d.ts +19 -5
  38. package/dist/esm/src/service/team/schemas/tactics.z.js +32 -33
  39. package/dist/esm/src/service/team/schemas/tactics.z.test.js +25 -92
  40. package/dist/esm/src/service/team/schemas/team.z.d.ts +19 -5
  41. package/dist/esm/src/service/team/tactics.d.ts +0 -2
  42. package/dist/esm/src/service/team/tactics.js +1 -2
  43. package/package.json +1 -1
@@ -94,7 +94,7 @@ describe('TacticsInputSchema — per-set tactics (systemSets / offensivePreferen
94
94
  { rotationSystem: '4-2', designatedSetters: [p1, p4] }
95
95
  ],
96
96
  offensivePreferenceSets: [
97
- [{ rotation: 1, weights: { [p2.id]: 60, [p3.id]: 40 } }],
97
+ [{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' } }],
98
98
  []
99
99
  ]
100
100
  }));
@@ -103,7 +103,7 @@ describe('TacticsInputSchema — per-set tactics (systemSets / offensivePreferen
103
103
  it('carries the per-set fields through Tactics.create parsing', () => {
104
104
  const res = TacticsInputSchema.safeParse(baseInput({
105
105
  systemSets: [{ rotationSystem: '5-1', designatedSetters: [p1] }],
106
- offensivePreferenceSets: [[{ rotation: 2, weights: { [p3.id]: 100 } }]]
106
+ offensivePreferenceSets: [[{ rotation: 2, priorities: { [p3.id]: 'HIGH' } }]]
107
107
  }));
108
108
  expect(res.success).toBe(true);
109
109
  if (res.success) {
@@ -152,7 +152,7 @@ describe('TacticsInputSchema — per-set tactics (systemSets / offensivePreferen
152
152
  });
153
153
  it('rejects a per-set preferences list with a duplicate rotation', () => {
154
154
  const res = TacticsInputSchema.safeParse(baseInput({
155
- offensivePreferenceSets: [[{ rotation: 1, weights: { [p2.id]: 100 } }, { rotation: 1, weights: { [p3.id]: 100 } }]]
155
+ offensivePreferenceSets: [[{ rotation: 1, priorities: { [p2.id]: 'HIGH' } }, { rotation: 1, priorities: { [p3.id]: 'HIGH' } }]]
156
156
  }));
157
157
  expect(res.success).toBe(false);
158
158
  if (!res.success) {
@@ -162,25 +162,38 @@ describe('TacticsInputSchema — per-set tactics (systemSets / offensivePreferen
162
162
  });
163
163
  it('rejects a per-set preferences map that keys a non-starter', () => {
164
164
  const res = TacticsInputSchema.safeParse(baseInput({
165
- offensivePreferenceSets: [[{ rotation: 1, weights: { [reserve.id]: 100 } }]]
165
+ offensivePreferenceSets: [[{ rotation: 1, priorities: { [reserve.id]: 'HIGH' } }]]
166
166
  }));
167
167
  expect(res.success).toBe(false);
168
168
  if (!res.success) {
169
169
  expect(res.error.issues.some(i => i.message === 'OFFENSIVE_PREFERENCE_ATTACKER_NOT_A_STARTER')).toBe(true);
170
170
  }
171
171
  });
172
- it('rejects offensive preference weights that do not sum to 100', () => {
172
+ it('accepts offensive priorities with no sum constraint', () => {
173
173
  const res = TacticsInputSchema.safeParse(baseInput({
174
- offensivePreferences: [{ rotation: 1, weights: { [p2.id]: 50, [p3.id]: 40 } }]
174
+ offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'LOW' } }]
175
+ }));
176
+ expect(res.success).toBe(true);
177
+ });
178
+ it('rejects an invalid attack priority value', () => {
179
+ const res = TacticsInputSchema.safeParse(baseInput({
180
+ offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'MEGA' } }]
175
181
  }));
176
182
  expect(res.success).toBe(false);
177
- if (!res.success) {
178
- expect(res.error.issues.some(i => i.message === 'OFFENSIVE_PREFERENCE_WEIGHTS_MUST_SUM_TO_100')).toBe(true);
179
- }
183
+ });
184
+ it('accepts a priority / tempo / no-block keyed by a designated substitute', () => {
185
+ const res = TacticsInputSchema.safeParse(baseInput({
186
+ lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [reserve] },
187
+ designatedSubs: [{ starter: p2, bench: reserve }],
188
+ offensivePreferences: [{ rotation: 1, priorities: { [reserve.id]: 'HIGH' }, tempos: { [reserve.id]: 'FAST' } }],
189
+ blockingPreferences: [{ rotation: 1, commit: {}, noBlock: { DEF_L: [reserve.id], DEF_M: [], DEF_R: [] } }],
190
+ basePositions: { coords: {}, receive: {}, receiveByPlayer: { 1: { [reserve.id]: false } } }
191
+ }));
192
+ expect(res.success).toBe(true);
180
193
  });
181
194
  it('accepts offensive preferences with a starter-keyed tempos map', () => {
182
195
  const res = TacticsInputSchema.safeParse(baseInput({
183
- offensivePreferences: [{ rotation: 1, weights: { [p2.id]: 60, [p3.id]: 40 }, tempos: { [p2.id]: 'FAST', [p3.id]: 'HIGH' } }]
196
+ offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' }, tempos: { [p2.id]: 'FAST', [p3.id]: 'HIGH' } }]
184
197
  }));
185
198
  expect(res.success).toBe(true);
186
199
  if (res.success) {
@@ -189,7 +202,7 @@ describe('TacticsInputSchema — per-set tactics (systemSets / offensivePreferen
189
202
  });
190
203
  it('rejects a tempos map keyed by a non-starter', () => {
191
204
  const res = TacticsInputSchema.safeParse(baseInput({
192
- offensivePreferences: [{ rotation: 1, weights: { [p2.id]: 100 }, tempos: { [reserve.id]: 'FAST' } }]
205
+ offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH' }, tempos: { [reserve.id]: 'FAST' } }]
193
206
  }));
194
207
  expect(res.success).toBe(false);
195
208
  if (!res.success) {
@@ -198,7 +211,7 @@ describe('TacticsInputSchema — per-set tactics (systemSets / offensivePreferen
198
211
  });
199
212
  it('rejects an invalid tempo value', () => {
200
213
  const res = TacticsInputSchema.safeParse(baseInput({
201
- offensivePreferences: [{ rotation: 1, weights: { [p2.id]: 100 }, tempos: { [p2.id]: 'SLOW' } }]
214
+ offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH' }, tempos: { [p2.id]: 'SLOW' } }]
202
215
  }));
203
216
  expect(res.success).toBe(false);
204
217
  });
@@ -323,83 +336,3 @@ describe('TacticsInputSchema — blocking preferences', () => {
323
336
  expect(res.success).toBe(false);
324
337
  });
325
338
  });
326
- describe('TacticsInputSchema — serve attack shares', () => {
327
- const country = makeCountry();
328
- const p1 = makePlayer(country);
329
- const p2 = makePlayer(country);
330
- const p3 = makePlayer(country);
331
- const p4 = makePlayer(country);
332
- const p5 = makePlayer(country);
333
- const p6 = makePlayer(country);
334
- const reserve = makePlayer(country);
335
- // p5 sits at zone 5 (back row) and is the configured libero replacement, so it may carry a serve share.
336
- function baseInput(overrides = {}) {
337
- return {
338
- lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [] },
339
- liberoReplacements: [p5],
340
- ...overrides
341
- };
342
- }
343
- it('accepts a serve share keyed by a libero replacement, value in band', () => {
344
- const res = TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 30 } }));
345
- expect(res.success).toBe(true);
346
- if (res.success)
347
- expect(res.data.serveAttackShares[p5.id]).toBe(30);
348
- });
349
- it('accepts 0 and 100 at the band edges', () => {
350
- expect(TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 0 } })).success).toBe(true);
351
- expect(TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 100 } })).success).toBe(true);
352
- });
353
- it('rejects a serve share keyed by a starter who is not a libero replacement', () => {
354
- const res = TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p2.id]: 30 } }));
355
- expect(res.success).toBe(false);
356
- if (!res.success) {
357
- expect(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_NOT_A_LIBERO_REPLACEMENT')).toBe(true);
358
- }
359
- });
360
- it('rejects a serve share keyed by a reserve', () => {
361
- const res = TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [reserve.id]: 30 } }));
362
- expect(res.success).toBe(false);
363
- if (!res.success) {
364
- expect(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_NOT_A_LIBERO_REPLACEMENT')).toBe(true);
365
- }
366
- });
367
- it('rejects an out-of-band serve share (over 100)', () => {
368
- const res = TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 101 } }));
369
- expect(res.success).toBe(false);
370
- if (!res.success) {
371
- expect(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_OUT_OF_BAND')).toBe(true);
372
- }
373
- });
374
- it('rejects a negative serve share', () => {
375
- const res = TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: -1 } }));
376
- expect(res.success).toBe(false);
377
- if (!res.success) {
378
- expect(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_OUT_OF_BAND')).toBe(true);
379
- }
380
- });
381
- it('validates independently of the offensive-preference sum-to-100 (never enters that total)', () => {
382
- // The other attackers' weights sum to exactly 100; the serve share on the libero replacement is separate
383
- // and must not push the rotation over 100 or otherwise fail.
384
- const res = TacticsInputSchema.safeParse(baseInput({
385
- offensivePreferences: [{ rotation: 1, weights: { [p2.id]: 50, [p3.id]: 50 } }],
386
- serveAttackShares: { [p5.id]: 40 }
387
- }));
388
- expect(res.success).toBe(true);
389
- });
390
- it('accepts a serve share on a per-set libero replacement', () => {
391
- // p6 is a back-row starter made a libero replacement only via liberoReplacementSets.
392
- const res = TacticsInputSchema.safeParse(baseInput({
393
- liberoReplacements: [],
394
- liberoReplacementSets: [[p6]],
395
- serveAttackShares: { [p6.id]: 25 }
396
- }));
397
- expect(res.success).toBe(true);
398
- });
399
- it('defaults serveAttackShares to an empty map when omitted', () => {
400
- const res = TacticsInputSchema.safeParse(baseInput());
401
- expect(res.success).toBe(true);
402
- if (res.success)
403
- expect(res.data.serveAttackShares).toEqual({});
404
- });
405
- });
@@ -269,23 +269,32 @@ export declare const TeamInputSchema: z.ZodObject<{
269
269
  designatedSetters: z.ZodDefault<z.ZodArray<z.ZodCustom<Player, Player>>>;
270
270
  offensivePreferences: z.ZodDefault<z.ZodArray<z.ZodObject<{
271
271
  rotation: z.ZodNumber;
272
- weights: z.ZodRecord<z.ZodString, z.ZodNumber>;
272
+ priorities: z.ZodRecord<z.ZodString, z.ZodEnum<{
273
+ HIGH: "HIGH";
274
+ MID: "MID";
275
+ LOW: "LOW";
276
+ NONE: "NONE";
277
+ }>>;
273
278
  tempos: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
274
- FAST: "FAST";
275
279
  HIGH: "HIGH";
280
+ FAST: "FAST";
276
281
  }>>>;
277
282
  }, z.core.$strip>>>;
278
- serveAttackShares: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
279
283
  systemSets: z.ZodOptional<z.ZodArray<z.ZodObject<{
280
284
  rotationSystem: z.ZodEnum<typeof import("..").RotationSystemEnum>;
281
285
  designatedSetters: z.ZodArray<z.ZodCustom<Player, Player>>;
282
286
  }, z.core.$strip>>>;
283
287
  offensivePreferenceSets: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
284
288
  rotation: z.ZodNumber;
285
- weights: z.ZodRecord<z.ZodString, z.ZodNumber>;
289
+ priorities: z.ZodRecord<z.ZodString, z.ZodEnum<{
290
+ HIGH: "HIGH";
291
+ MID: "MID";
292
+ LOW: "LOW";
293
+ NONE: "NONE";
294
+ }>>;
286
295
  tempos: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
287
- FAST: "FAST";
288
296
  HIGH: "HIGH";
297
+ FAST: "FAST";
289
298
  }>>>;
290
299
  }, z.core.$strip>>>>;
291
300
  blockingPreferences: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -312,7 +321,12 @@ export declare const TeamInputSchema: z.ZodObject<{
312
321
  r: z.ZodNumber;
313
322
  }, z.core.$strip>>>>;
314
323
  receive: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodBoolean>>;
324
+ receiveByPlayer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodBoolean>>>;
315
325
  blocking: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodBoolean>>>>;
326
+ attackContact: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
327
+ d: z.ZodNumber;
328
+ r: z.ZodNumber;
329
+ }, z.core.$strip>>>>;
316
330
  }, z.core.$strip>>;
317
331
  replaceKnockedImmediately: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodBoolean>>;
318
332
  injuryReplacements: z.ZodDefault<z.ZodArray<z.ZodObject<{
@@ -35,7 +35,6 @@ export interface TacticsOpts {
35
35
  readonly rotationSystem: RotationSystemEnum;
36
36
  readonly designatedSetters: Player[];
37
37
  readonly offensivePreferences: OffensivePreference[];
38
- readonly serveAttackShares: Record<string, number>;
39
38
  readonly systemSets?: SystemSet[];
40
39
  readonly offensivePreferenceSets?: OffensivePreference[][];
41
40
  readonly replaceKnockedImmediately: Record<string, boolean>;
@@ -57,7 +56,6 @@ export declare class Tactics {
57
56
  readonly rotationSystem: RotationSystemEnum;
58
57
  readonly designatedSetters: Player[];
59
58
  readonly offensivePreferences: OffensivePreference[];
60
- readonly serveAttackShares: Record<string, number>;
61
59
  readonly systemSets?: SystemSet[];
62
60
  readonly offensivePreferenceSets?: OffensivePreference[][];
63
61
  readonly replaceKnockedImmediately: Record<string, boolean>;
@@ -15,7 +15,7 @@ export class Tactics {
15
15
  }
16
16
  return new Tactics(result.data);
17
17
  }
18
- constructor({ lineup, liberoReplacements, receiveRotationOffset = false, designatedSubs = [], substitutionBand = EnergyBand.TIRED, secondLibero, liberoSub, liberoReplacementSets, rotationSystem = RotationSystemEnum.SIX_ZERO, designatedSetters = [], offensivePreferences = [], serveAttackShares = {}, systemSets, offensivePreferenceSets, replaceKnockedImmediately = {}, injuryReplacements = [], liberoInjury, blockingPreferences = [], blockingPreferenceSets, basePositions }) {
18
+ constructor({ lineup, liberoReplacements, receiveRotationOffset = false, designatedSubs = [], substitutionBand = EnergyBand.TIRED, secondLibero, liberoSub, liberoReplacementSets, rotationSystem = RotationSystemEnum.SIX_ZERO, designatedSetters = [], offensivePreferences = [], systemSets, offensivePreferenceSets, replaceKnockedImmediately = {}, injuryReplacements = [], liberoInjury, blockingPreferences = [], blockingPreferenceSets, basePositions }) {
19
19
  this.lineup = lineup;
20
20
  this.liberoReplacements = liberoReplacements;
21
21
  this.receiveRotationOffset = receiveRotationOffset;
@@ -27,7 +27,6 @@ export class Tactics {
27
27
  this.rotationSystem = rotationSystem;
28
28
  this.designatedSetters = designatedSetters;
29
29
  this.offensivePreferences = offensivePreferences;
30
- this.serveAttackShares = serveAttackShares;
31
30
  this.systemSets = systemSets;
32
31
  this.offensivePreferenceSets = offensivePreferenceSets;
33
32
  this.replaceKnockedImmediately = replaceKnockedImmediately;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "volleyballsimtypes",
3
- "version": "0.0.514",
3
+ "version": "0.0.516",
4
4
  "description": "vbsim types",
5
5
  "main": "./dist/cjs/src/index.js",
6
6
  "module": "./dist/esm/src/index.js",