volleyballsimtypes 0.0.515 → 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.
- package/dist/cjs/src/api/index.d.ts +1 -2
- package/dist/cjs/src/api/tactics-player-refs.js +2 -2
- package/dist/cjs/src/data/models/tactics.d.ts +2 -4
- package/dist/cjs/src/data/models/tactics.js +0 -5
- package/dist/cjs/src/data/transformers/tactics.js +4 -36
- package/dist/cjs/src/data/transformers/tactics.test.js +9 -46
- package/dist/cjs/src/service/team/attack-priority.d.ts +3 -0
- package/dist/cjs/src/service/team/attack-priority.js +11 -0
- package/dist/cjs/src/service/team/base-config.d.ts +1 -0
- package/dist/cjs/src/service/team/index.d.ts +1 -0
- package/dist/cjs/src/service/team/index.js +1 -0
- package/dist/cjs/src/service/team/offensive-preference.d.ts +2 -1
- package/dist/cjs/src/service/team/schemas/tactics.z.d.ts +15 -5
- package/dist/cjs/src/service/team/schemas/tactics.z.js +28 -32
- package/dist/cjs/src/service/team/schemas/tactics.z.test.js +25 -92
- package/dist/cjs/src/service/team/schemas/team.z.d.ts +15 -5
- package/dist/cjs/src/service/team/tactics.d.ts +0 -2
- package/dist/cjs/src/service/team/tactics.js +1 -2
- package/dist/esm/src/api/index.d.ts +1 -2
- package/dist/esm/src/api/tactics-player-refs.js +2 -2
- package/dist/esm/src/data/models/tactics.d.ts +2 -4
- package/dist/esm/src/data/models/tactics.js +0 -5
- package/dist/esm/src/data/transformers/tactics.js +4 -36
- package/dist/esm/src/data/transformers/tactics.test.js +9 -46
- package/dist/esm/src/service/team/attack-priority.d.ts +3 -0
- package/dist/esm/src/service/team/attack-priority.js +8 -0
- package/dist/esm/src/service/team/base-config.d.ts +1 -0
- package/dist/esm/src/service/team/index.d.ts +1 -0
- package/dist/esm/src/service/team/index.js +1 -0
- package/dist/esm/src/service/team/offensive-preference.d.ts +2 -1
- package/dist/esm/src/service/team/schemas/tactics.z.d.ts +15 -5
- package/dist/esm/src/service/team/schemas/tactics.z.js +28 -32
- package/dist/esm/src/service/team/schemas/tactics.z.test.js +25 -92
- package/dist/esm/src/service/team/schemas/team.z.d.ts +15 -5
- package/dist/esm/src/service/team/tactics.d.ts +0 -2
- package/dist/esm/src/service/team/tactics.js +1 -2
- package/package.json +1 -1
|
@@ -96,7 +96,7 @@ const test_helpers_1 = require("../../test-helpers");
|
|
|
96
96
|
{ rotationSystem: '4-2', designatedSetters: [p1, p4] }
|
|
97
97
|
],
|
|
98
98
|
offensivePreferenceSets: [
|
|
99
|
-
[{ rotation: 1,
|
|
99
|
+
[{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' } }],
|
|
100
100
|
[]
|
|
101
101
|
]
|
|
102
102
|
}));
|
|
@@ -105,7 +105,7 @@ const test_helpers_1 = require("../../test-helpers");
|
|
|
105
105
|
(0, globals_1.it)('carries the per-set fields through Tactics.create parsing', () => {
|
|
106
106
|
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
107
107
|
systemSets: [{ rotationSystem: '5-1', designatedSetters: [p1] }],
|
|
108
|
-
offensivePreferenceSets: [[{ rotation: 2,
|
|
108
|
+
offensivePreferenceSets: [[{ rotation: 2, priorities: { [p3.id]: 'HIGH' } }]]
|
|
109
109
|
}));
|
|
110
110
|
(0, globals_1.expect)(res.success).toBe(true);
|
|
111
111
|
if (res.success) {
|
|
@@ -154,7 +154,7 @@ const test_helpers_1 = require("../../test-helpers");
|
|
|
154
154
|
});
|
|
155
155
|
(0, globals_1.it)('rejects a per-set preferences list with a duplicate rotation', () => {
|
|
156
156
|
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
157
|
-
offensivePreferenceSets: [[{ rotation: 1,
|
|
157
|
+
offensivePreferenceSets: [[{ rotation: 1, priorities: { [p2.id]: 'HIGH' } }, { rotation: 1, priorities: { [p3.id]: 'HIGH' } }]]
|
|
158
158
|
}));
|
|
159
159
|
(0, globals_1.expect)(res.success).toBe(false);
|
|
160
160
|
if (!res.success) {
|
|
@@ -164,25 +164,38 @@ const test_helpers_1 = require("../../test-helpers");
|
|
|
164
164
|
});
|
|
165
165
|
(0, globals_1.it)('rejects a per-set preferences map that keys a non-starter', () => {
|
|
166
166
|
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
167
|
-
offensivePreferenceSets: [[{ rotation: 1,
|
|
167
|
+
offensivePreferenceSets: [[{ rotation: 1, priorities: { [reserve.id]: 'HIGH' } }]]
|
|
168
168
|
}));
|
|
169
169
|
(0, globals_1.expect)(res.success).toBe(false);
|
|
170
170
|
if (!res.success) {
|
|
171
171
|
(0, globals_1.expect)(res.error.issues.some(i => i.message === 'OFFENSIVE_PREFERENCE_ATTACKER_NOT_A_STARTER')).toBe(true);
|
|
172
172
|
}
|
|
173
173
|
});
|
|
174
|
-
(0, globals_1.it)('
|
|
174
|
+
(0, globals_1.it)('accepts offensive priorities with no sum constraint', () => {
|
|
175
175
|
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
176
|
-
offensivePreferences: [{ rotation: 1,
|
|
176
|
+
offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'LOW' } }]
|
|
177
|
+
}));
|
|
178
|
+
(0, globals_1.expect)(res.success).toBe(true);
|
|
179
|
+
});
|
|
180
|
+
(0, globals_1.it)('rejects an invalid attack priority value', () => {
|
|
181
|
+
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
182
|
+
offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'MEGA' } }]
|
|
177
183
|
}));
|
|
178
184
|
(0, globals_1.expect)(res.success).toBe(false);
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
185
|
+
});
|
|
186
|
+
(0, globals_1.it)('accepts a priority / tempo / no-block keyed by a designated substitute', () => {
|
|
187
|
+
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
188
|
+
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [reserve] },
|
|
189
|
+
designatedSubs: [{ starter: p2, bench: reserve }],
|
|
190
|
+
offensivePreferences: [{ rotation: 1, priorities: { [reserve.id]: 'HIGH' }, tempos: { [reserve.id]: 'FAST' } }],
|
|
191
|
+
blockingPreferences: [{ rotation: 1, commit: {}, noBlock: { DEF_L: [reserve.id], DEF_M: [], DEF_R: [] } }],
|
|
192
|
+
basePositions: { coords: {}, receive: {}, receiveByPlayer: { 1: { [reserve.id]: false } } }
|
|
193
|
+
}));
|
|
194
|
+
(0, globals_1.expect)(res.success).toBe(true);
|
|
182
195
|
});
|
|
183
196
|
(0, globals_1.it)('accepts offensive preferences with a starter-keyed tempos map', () => {
|
|
184
197
|
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
185
|
-
offensivePreferences: [{ rotation: 1,
|
|
198
|
+
offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' }, tempos: { [p2.id]: 'FAST', [p3.id]: 'HIGH' } }]
|
|
186
199
|
}));
|
|
187
200
|
(0, globals_1.expect)(res.success).toBe(true);
|
|
188
201
|
if (res.success) {
|
|
@@ -191,7 +204,7 @@ const test_helpers_1 = require("../../test-helpers");
|
|
|
191
204
|
});
|
|
192
205
|
(0, globals_1.it)('rejects a tempos map keyed by a non-starter', () => {
|
|
193
206
|
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
194
|
-
offensivePreferences: [{ rotation: 1,
|
|
207
|
+
offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH' }, tempos: { [reserve.id]: 'FAST' } }]
|
|
195
208
|
}));
|
|
196
209
|
(0, globals_1.expect)(res.success).toBe(false);
|
|
197
210
|
if (!res.success) {
|
|
@@ -200,7 +213,7 @@ const test_helpers_1 = require("../../test-helpers");
|
|
|
200
213
|
});
|
|
201
214
|
(0, globals_1.it)('rejects an invalid tempo value', () => {
|
|
202
215
|
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
203
|
-
offensivePreferences: [{ rotation: 1,
|
|
216
|
+
offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH' }, tempos: { [p2.id]: 'SLOW' } }]
|
|
204
217
|
}));
|
|
205
218
|
(0, globals_1.expect)(res.success).toBe(false);
|
|
206
219
|
});
|
|
@@ -325,83 +338,3 @@ const test_helpers_1 = require("../../test-helpers");
|
|
|
325
338
|
(0, globals_1.expect)(res.success).toBe(false);
|
|
326
339
|
});
|
|
327
340
|
});
|
|
328
|
-
(0, globals_1.describe)('TacticsInputSchema — serve attack shares', () => {
|
|
329
|
-
const country = (0, test_helpers_1.makeCountry)();
|
|
330
|
-
const p1 = (0, test_helpers_1.makePlayer)(country);
|
|
331
|
-
const p2 = (0, test_helpers_1.makePlayer)(country);
|
|
332
|
-
const p3 = (0, test_helpers_1.makePlayer)(country);
|
|
333
|
-
const p4 = (0, test_helpers_1.makePlayer)(country);
|
|
334
|
-
const p5 = (0, test_helpers_1.makePlayer)(country);
|
|
335
|
-
const p6 = (0, test_helpers_1.makePlayer)(country);
|
|
336
|
-
const reserve = (0, test_helpers_1.makePlayer)(country);
|
|
337
|
-
// p5 sits at zone 5 (back row) and is the configured libero replacement, so it may carry a serve share.
|
|
338
|
-
function baseInput(overrides = {}) {
|
|
339
|
-
return {
|
|
340
|
-
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [] },
|
|
341
|
-
liberoReplacements: [p5],
|
|
342
|
-
...overrides
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
(0, globals_1.it)('accepts a serve share keyed by a libero replacement, value in band', () => {
|
|
346
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 30 } }));
|
|
347
|
-
(0, globals_1.expect)(res.success).toBe(true);
|
|
348
|
-
if (res.success)
|
|
349
|
-
(0, globals_1.expect)(res.data.serveAttackShares[p5.id]).toBe(30);
|
|
350
|
-
});
|
|
351
|
-
(0, globals_1.it)('accepts 0 and 100 at the band edges', () => {
|
|
352
|
-
(0, globals_1.expect)(tactics_z_1.TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 0 } })).success).toBe(true);
|
|
353
|
-
(0, globals_1.expect)(tactics_z_1.TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 100 } })).success).toBe(true);
|
|
354
|
-
});
|
|
355
|
-
(0, globals_1.it)('rejects a serve share keyed by a starter who is not a libero replacement', () => {
|
|
356
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p2.id]: 30 } }));
|
|
357
|
-
(0, globals_1.expect)(res.success).toBe(false);
|
|
358
|
-
if (!res.success) {
|
|
359
|
-
(0, globals_1.expect)(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_NOT_A_LIBERO_REPLACEMENT')).toBe(true);
|
|
360
|
-
}
|
|
361
|
-
});
|
|
362
|
-
(0, globals_1.it)('rejects a serve share keyed by a reserve', () => {
|
|
363
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [reserve.id]: 30 } }));
|
|
364
|
-
(0, globals_1.expect)(res.success).toBe(false);
|
|
365
|
-
if (!res.success) {
|
|
366
|
-
(0, globals_1.expect)(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_NOT_A_LIBERO_REPLACEMENT')).toBe(true);
|
|
367
|
-
}
|
|
368
|
-
});
|
|
369
|
-
(0, globals_1.it)('rejects an out-of-band serve share (over 100)', () => {
|
|
370
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: 101 } }));
|
|
371
|
-
(0, globals_1.expect)(res.success).toBe(false);
|
|
372
|
-
if (!res.success) {
|
|
373
|
-
(0, globals_1.expect)(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_OUT_OF_BAND')).toBe(true);
|
|
374
|
-
}
|
|
375
|
-
});
|
|
376
|
-
(0, globals_1.it)('rejects a negative serve share', () => {
|
|
377
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({ serveAttackShares: { [p5.id]: -1 } }));
|
|
378
|
-
(0, globals_1.expect)(res.success).toBe(false);
|
|
379
|
-
if (!res.success) {
|
|
380
|
-
(0, globals_1.expect)(res.error.issues.some(i => i.message === 'SERVE_ATTACK_SHARE_OUT_OF_BAND')).toBe(true);
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
(0, globals_1.it)('validates independently of the offensive-preference sum-to-100 (never enters that total)', () => {
|
|
384
|
-
// The other attackers' weights sum to exactly 100; the serve share on the libero replacement is separate
|
|
385
|
-
// and must not push the rotation over 100 or otherwise fail.
|
|
386
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
387
|
-
offensivePreferences: [{ rotation: 1, weights: { [p2.id]: 50, [p3.id]: 50 } }],
|
|
388
|
-
serveAttackShares: { [p5.id]: 40 }
|
|
389
|
-
}));
|
|
390
|
-
(0, globals_1.expect)(res.success).toBe(true);
|
|
391
|
-
});
|
|
392
|
-
(0, globals_1.it)('accepts a serve share on a per-set libero replacement', () => {
|
|
393
|
-
// p6 is a back-row starter made a libero replacement only via liberoReplacementSets.
|
|
394
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput({
|
|
395
|
-
liberoReplacements: [],
|
|
396
|
-
liberoReplacementSets: [[p6]],
|
|
397
|
-
serveAttackShares: { [p6.id]: 25 }
|
|
398
|
-
}));
|
|
399
|
-
(0, globals_1.expect)(res.success).toBe(true);
|
|
400
|
-
});
|
|
401
|
-
(0, globals_1.it)('defaults serveAttackShares to an empty map when omitted', () => {
|
|
402
|
-
const res = tactics_z_1.TacticsInputSchema.safeParse(baseInput());
|
|
403
|
-
(0, globals_1.expect)(res.success).toBe(true);
|
|
404
|
-
if (res.success)
|
|
405
|
-
(0, globals_1.expect)(res.data.serveAttackShares).toEqual({});
|
|
406
|
-
});
|
|
407
|
-
});
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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,6 +321,7 @@ 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>>>>;
|
|
316
326
|
attackContact: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
317
327
|
d: z.ZodNumber;
|
|
@@ -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>;
|
|
@@ -18,7 +18,7 @@ class Tactics {
|
|
|
18
18
|
}
|
|
19
19
|
return new Tactics(result.data);
|
|
20
20
|
}
|
|
21
|
-
constructor({ lineup, liberoReplacements, receiveRotationOffset = false, designatedSubs = [], substitutionBand = energy_band_1.EnergyBand.TIRED, secondLibero, liberoSub, liberoReplacementSets, rotationSystem = rotation_system_1.RotationSystemEnum.SIX_ZERO, designatedSetters = [], offensivePreferences = [],
|
|
21
|
+
constructor({ lineup, liberoReplacements, receiveRotationOffset = false, designatedSubs = [], substitutionBand = energy_band_1.EnergyBand.TIRED, secondLibero, liberoSub, liberoReplacementSets, rotationSystem = rotation_system_1.RotationSystemEnum.SIX_ZERO, designatedSetters = [], offensivePreferences = [], systemSets, offensivePreferenceSets, replaceKnockedImmediately = {}, injuryReplacements = [], liberoInjury, blockingPreferences = [], blockingPreferenceSets, basePositions }) {
|
|
22
22
|
this.lineup = lineup;
|
|
23
23
|
this.liberoReplacements = liberoReplacements;
|
|
24
24
|
this.receiveRotationOffset = receiveRotationOffset;
|
|
@@ -30,7 +30,6 @@ class Tactics {
|
|
|
30
30
|
this.rotationSystem = rotationSystem;
|
|
31
31
|
this.designatedSetters = designatedSetters;
|
|
32
32
|
this.offensivePreferences = offensivePreferences;
|
|
33
|
-
this.serveAttackShares = serveAttackShares;
|
|
34
33
|
this.systemSets = systemSets;
|
|
35
34
|
this.offensivePreferenceSets = offensivePreferenceSets;
|
|
36
35
|
this.replaceKnockedImmediately = replaceKnockedImmediately;
|
|
@@ -97,7 +97,7 @@ export interface ApiDesignatedSub extends ApiSetSubConfig {
|
|
|
97
97
|
}
|
|
98
98
|
export interface ApiOffensivePreference {
|
|
99
99
|
rotation: number;
|
|
100
|
-
|
|
100
|
+
priorities: Record<string, 'HIGH' | 'MID' | 'LOW' | 'NONE'>;
|
|
101
101
|
tempos?: Record<string, 'FAST' | 'HIGH'>;
|
|
102
102
|
}
|
|
103
103
|
export interface ApiBlockingPreference {
|
|
@@ -140,7 +140,6 @@ export interface Tactics {
|
|
|
140
140
|
offensivePreferences: ApiOffensivePreference[];
|
|
141
141
|
systemSets?: ApiSystemSet[];
|
|
142
142
|
offensivePreferenceSets?: ApiOffensivePreference[][];
|
|
143
|
-
serveAttackShares?: Record<string, number>;
|
|
144
143
|
basePositions?: BaseConfig;
|
|
145
144
|
blockingPreferences: ApiBlockingPreference[];
|
|
146
145
|
blockingPreferenceSets?: ApiBlockingPreference[][];
|
|
@@ -23,9 +23,9 @@ export function collectTacticsPlayerIds(config) {
|
|
|
23
23
|
config.secondLibero,
|
|
24
24
|
...((config.liberoReplacementSets ?? []).flat()),
|
|
25
25
|
...(config.designatedSetters ?? []),
|
|
26
|
-
...((config.offensivePreferences ?? []).flatMap(p => Object.keys(p.
|
|
26
|
+
...((config.offensivePreferences ?? []).flatMap(p => Object.keys(p.priorities))),
|
|
27
27
|
...((config.systemSets ?? []).flatMap(s => s.designatedSetters)),
|
|
28
|
-
...((config.offensivePreferenceSets ?? []).flat().flatMap(p => Object.keys(p.
|
|
28
|
+
...((config.offensivePreferenceSets ?? []).flat().flatMap(p => Object.keys(p.priorities))),
|
|
29
29
|
...((config.blockingPreferences ?? []).flatMap(p => [...Object.keys(p.commit ?? {}), ...Object.values(p.noBlock ?? {}).flat()])),
|
|
30
30
|
...((config.blockingPreferenceSets ?? []).flat().flatMap(p => [...Object.keys(p.commit ?? {}), ...Object.values(p.noBlock ?? {}).flat()])),
|
|
31
31
|
// Injury replacements reference reserves (roster players outside the lineup); roster membership is the only
|
|
@@ -31,7 +31,7 @@ export interface DesignatedSubAttributes extends SetSubConfigAttributes {
|
|
|
31
31
|
}
|
|
32
32
|
export interface OffensivePreferenceAttributes {
|
|
33
33
|
rotation: number;
|
|
34
|
-
|
|
34
|
+
priorities: Record<PlayerId, 'HIGH' | 'MID' | 'LOW' | 'NONE'>;
|
|
35
35
|
tempos?: Record<PlayerId, 'FAST' | 'HIGH'>;
|
|
36
36
|
}
|
|
37
37
|
export interface BlockingPreferenceAttributes {
|
|
@@ -77,7 +77,6 @@ export interface TacticsAttributes {
|
|
|
77
77
|
offensive_preferences: OffensivePreferenceAttributes[];
|
|
78
78
|
system_sets?: SystemSetAttributes[];
|
|
79
79
|
offensive_preference_sets?: OffensivePreferenceAttributes[][];
|
|
80
|
-
serve_attack_shares: Record<PlayerId, number>;
|
|
81
80
|
replace_knocked_immediately?: Record<PlayerId, boolean>;
|
|
82
81
|
injury_replacements?: InjuryReplacementAttributes[];
|
|
83
82
|
libero_injury?: LiberoInjuryAttributes;
|
|
@@ -87,7 +86,7 @@ export interface TacticsAttributes {
|
|
|
87
86
|
}
|
|
88
87
|
export type TacticsPk = 'team_id';
|
|
89
88
|
export type TacticsId = TacticsModel[TacticsPk];
|
|
90
|
-
export type TacticsOptionalAttributes = 'lineup' | 'libero_replacements' | 'receive_rotation_offset' | 'designated_subs' | 'substitution_band' | 'second_libero' | 'libero_sub' | 'libero_replacement_sets' | 'rotation_system' | 'designated_setters' | 'offensive_preferences' | 'system_sets' | 'offensive_preference_sets' | '
|
|
89
|
+
export type TacticsOptionalAttributes = 'lineup' | 'libero_replacements' | 'receive_rotation_offset' | 'designated_subs' | 'substitution_band' | 'second_libero' | 'libero_sub' | 'libero_replacement_sets' | 'rotation_system' | 'designated_setters' | 'offensive_preferences' | 'system_sets' | 'offensive_preference_sets' | 'replace_knocked_immediately' | 'injury_replacements' | 'libero_injury' | 'blocking_preferences' | 'blocking_preference_sets' | 'base_positions';
|
|
91
90
|
export type TacticsCreationAttributes = Optional<TacticsAttributes, TacticsOptionalAttributes>;
|
|
92
91
|
export declare class TacticsModel extends Model<TacticsAttributes, TacticsCreationAttributes> implements TacticsAttributes {
|
|
93
92
|
team_id: string;
|
|
@@ -104,7 +103,6 @@ export declare class TacticsModel extends Model<TacticsAttributes, TacticsCreati
|
|
|
104
103
|
offensive_preferences: OffensivePreferenceAttributes[];
|
|
105
104
|
system_sets?: SystemSetAttributes[];
|
|
106
105
|
offensive_preference_sets?: OffensivePreferenceAttributes[][];
|
|
107
|
-
serve_attack_shares: Record<PlayerId, number>;
|
|
108
106
|
replace_knocked_immediately?: Record<PlayerId, boolean>;
|
|
109
107
|
injury_replacements?: InjuryReplacementAttributes[];
|
|
110
108
|
libero_injury?: LiberoInjuryAttributes;
|
|
@@ -72,11 +72,6 @@ export class TacticsModel extends Model {
|
|
|
72
72
|
type: DataTypes.JSONB,
|
|
73
73
|
allowNull: true
|
|
74
74
|
},
|
|
75
|
-
serve_attack_shares: {
|
|
76
|
-
type: DataTypes.JSONB,
|
|
77
|
-
allowNull: false,
|
|
78
|
-
defaultValue: {}
|
|
79
|
-
},
|
|
80
75
|
replace_knocked_immediately: {
|
|
81
76
|
type: DataTypes.JSONB,
|
|
82
77
|
allowNull: true
|
|
@@ -67,7 +67,7 @@ function transformToAttributes(tactics, teamId) {
|
|
|
67
67
|
designated_setters: tactics.designatedSetters.map((s) => s.id),
|
|
68
68
|
offensive_preferences: tactics.offensivePreferences.map(p => ({
|
|
69
69
|
rotation: p.rotation,
|
|
70
|
-
|
|
70
|
+
priorities: p.priorities,
|
|
71
71
|
tempos: p.tempos
|
|
72
72
|
})),
|
|
73
73
|
system_sets: tactics.systemSets?.map(s => ({
|
|
@@ -76,10 +76,9 @@ function transformToAttributes(tactics, teamId) {
|
|
|
76
76
|
})),
|
|
77
77
|
offensive_preference_sets: tactics.offensivePreferenceSets?.map(prefs => prefs.map(p => ({
|
|
78
78
|
rotation: p.rotation,
|
|
79
|
-
|
|
79
|
+
priorities: p.priorities,
|
|
80
80
|
tempos: p.tempos
|
|
81
81
|
}))),
|
|
82
|
-
serve_attack_shares: tactics.serveAttackShares ?? {},
|
|
83
82
|
base_positions: tactics.basePositions,
|
|
84
83
|
blocking_preferences: tactics.blockingPreferences.map(p => ({ rotation: p.rotation, commit: p.commit, noBlock: p.noBlock })),
|
|
85
84
|
blocking_preference_sets: tactics.blockingPreferenceSets?.map(prefs => prefs.map(p => ({ rotation: p.rotation, commit: p.commit, noBlock: p.noBlock }))),
|
|
@@ -175,7 +174,7 @@ function transformToObject(model, roster) {
|
|
|
175
174
|
designatedSetters: (model.designated_setters ?? []).map((id) => findPlayer(id, roster)),
|
|
176
175
|
offensivePreferences: (model.offensive_preferences ?? []).map(p => ({
|
|
177
176
|
rotation: p.rotation,
|
|
178
|
-
|
|
177
|
+
priorities: p.priorities,
|
|
179
178
|
tempos: p.tempos
|
|
180
179
|
})),
|
|
181
180
|
systemSets: model.system_sets?.map(s => ({
|
|
@@ -184,24 +183,9 @@ function transformToObject(model, roster) {
|
|
|
184
183
|
})),
|
|
185
184
|
offensivePreferenceSets: model.offensive_preference_sets?.map(prefs => prefs.map(p => ({
|
|
186
185
|
rotation: p.rotation,
|
|
187
|
-
|
|
186
|
+
priorities: p.priorities,
|
|
188
187
|
tempos: p.tempos
|
|
189
188
|
}))),
|
|
190
|
-
// LENIENT: keep only serve shares keyed by a current libero-replacement (flat or per-set) with a value in the
|
|
191
|
-
// 0-100 band, so a stale key (a released player, or a libero-replacement config change) can never fail schema
|
|
192
|
-
// validation and crash a team load; a dropped key = no serve share.
|
|
193
|
-
serveAttackShares: (() => {
|
|
194
|
-
const liberoReplacementIds = new Set([
|
|
195
|
-
...model.libero_replacements,
|
|
196
|
-
...(model.libero_replacement_sets ?? []).flat()
|
|
197
|
-
]);
|
|
198
|
-
const healed = {};
|
|
199
|
-
for (const [id, value] of Object.entries(model.serve_attack_shares ?? {})) {
|
|
200
|
-
if (liberoReplacementIds.has(id) && typeof value === 'number' && value >= 0 && value <= 100)
|
|
201
|
-
healed[id] = value;
|
|
202
|
-
}
|
|
203
|
-
return healed;
|
|
204
|
-
})(),
|
|
205
189
|
basePositions: model.base_positions ?? undefined,
|
|
206
190
|
blockingPreferences: (model.blocking_preferences ?? []).map(p => ({ rotation: p.rotation, commit: p.commit, noBlock: p.noBlock })),
|
|
207
191
|
blockingPreferenceSets: model.blocking_preference_sets?.map(prefs => prefs.map(p => ({ rotation: p.rotation, commit: p.commit, noBlock: p.noBlock }))),
|
|
@@ -348,21 +332,6 @@ function tacticsColumnsToApiDto(model) {
|
|
|
348
332
|
offensivePreferences: model.offensive_preferences,
|
|
349
333
|
systemSets: model.system_sets,
|
|
350
334
|
offensivePreferenceSets: model.offensive_preference_sets,
|
|
351
|
-
// Same stale-data policy as the heals below: only serve shares keyed by a current libero-replacement (flat or
|
|
352
|
-
// per-set) with a value in the 0-100 band survive; an empty map surfaces as absent so the UI never reloads and
|
|
353
|
-
// re-emits a stale key.
|
|
354
|
-
serveAttackShares: (() => {
|
|
355
|
-
const liberoReplacementIds = new Set([
|
|
356
|
-
...model.libero_replacements,
|
|
357
|
-
...(model.libero_replacement_sets ?? []).flat()
|
|
358
|
-
]);
|
|
359
|
-
const healed = {};
|
|
360
|
-
for (const [id, value] of Object.entries(model.serve_attack_shares ?? {})) {
|
|
361
|
-
if (liberoReplacementIds.has(id) && typeof value === 'number' && value >= 0 && value <= 100)
|
|
362
|
-
healed[id] = value;
|
|
363
|
-
}
|
|
364
|
-
return Object.keys(healed).length > 0 ? healed : undefined;
|
|
365
|
-
})(),
|
|
366
335
|
basePositions: model.base_positions ?? undefined,
|
|
367
336
|
blockingPreferences: model.blocking_preferences,
|
|
368
337
|
blockingPreferenceSets: model.blocking_preference_sets,
|
|
@@ -471,7 +440,6 @@ function apiTacticsConfigToAttributes(config, teamId) {
|
|
|
471
440
|
offensive_preferences: config.offensivePreferences,
|
|
472
441
|
system_sets: config.systemSets,
|
|
473
442
|
offensive_preference_sets: config.offensivePreferenceSets,
|
|
474
|
-
serve_attack_shares: config.serveAttackShares ?? {},
|
|
475
443
|
base_positions: config.basePositions,
|
|
476
444
|
blocking_preferences: config.blockingPreferences ?? [],
|
|
477
445
|
blocking_preference_sets: config.blockingPreferenceSets,
|
|
@@ -24,7 +24,7 @@ function makeTactics(designatedSubs) {
|
|
|
24
24
|
libero_replacement_sets: undefined,
|
|
25
25
|
rotation_system: '5-1',
|
|
26
26
|
designated_setters: ['lf'],
|
|
27
|
-
offensive_preferences: [{ rotation: 1,
|
|
27
|
+
offensive_preferences: [{ rotation: 1, priorities: { lf: 'HIGH', rf: 'MID' } }],
|
|
28
28
|
blocking_preferences: []
|
|
29
29
|
};
|
|
30
30
|
}
|
|
@@ -36,7 +36,7 @@ describe('tacticsColumnsToApiDto()', () => {
|
|
|
36
36
|
expect(dto.rotationSystem).toBe('5-1');
|
|
37
37
|
expect(dto.liberoReplacements).toEqual(['lf']);
|
|
38
38
|
expect(dto.lineup.bench).toEqual(['b1', 'b2']);
|
|
39
|
-
expect(dto.offensivePreferences).toEqual([{ rotation: 1,
|
|
39
|
+
expect(dto.offensivePreferences).toEqual([{ rotation: 1, priorities: { lf: 'HIGH', rf: 'MID' } }]);
|
|
40
40
|
});
|
|
41
41
|
it('converts a legacy isPinchServer entry to a unified pinch server (conditions kept, no mode)', () => {
|
|
42
42
|
const dto = tacticsColumnsToApiDto(makeTactics([
|
|
@@ -131,32 +131,16 @@ describe('tacticsColumnsToApiDto()', () => {
|
|
|
131
131
|
it('passes per-set tactics columns through to the API DTO shape', () => {
|
|
132
132
|
const model = makeTactics([]);
|
|
133
133
|
model.system_sets = [{ rotationSystem: RotationSystemEnum.FIVE_ONE, designatedSetters: ['lf'] }];
|
|
134
|
-
model.offensive_preference_sets = [[{ rotation: 1,
|
|
134
|
+
model.offensive_preference_sets = [[{ rotation: 1, priorities: { rf: 'HIGH', mf: 'MID' } }]];
|
|
135
135
|
const dto = tacticsColumnsToApiDto(model);
|
|
136
136
|
expect(dto.systemSets).toEqual([{ rotationSystem: '5-1', designatedSetters: ['lf'] }]);
|
|
137
|
-
expect(dto.offensivePreferenceSets).toEqual([[{ rotation: 1,
|
|
137
|
+
expect(dto.offensivePreferenceSets).toEqual([[{ rotation: 1, priorities: { rf: 'HIGH', mf: 'MID' } }]]);
|
|
138
138
|
});
|
|
139
139
|
it('leaves the per-set DTO fields undefined when the columns are absent', () => {
|
|
140
140
|
const dto = tacticsColumnsToApiDto(makeTactics([]));
|
|
141
141
|
expect(dto.systemSets).toBeUndefined();
|
|
142
142
|
expect(dto.offensivePreferenceSets).toBeUndefined();
|
|
143
143
|
});
|
|
144
|
-
it('surfaces serve attack shares keyed by a libero replacement', () => {
|
|
145
|
-
const model = makeTactics([]);
|
|
146
|
-
model.serve_attack_shares = { lf: 30 }; // lf is the configured libero_replacement
|
|
147
|
-
const dto = tacticsColumnsToApiDto(model);
|
|
148
|
-
expect(dto.serveAttackShares).toEqual({ lf: 30 });
|
|
149
|
-
});
|
|
150
|
-
it('drops a serve attack share keyed by a non-libero-replacement (stale heal)', () => {
|
|
151
|
-
const model = makeTactics([]);
|
|
152
|
-
model.serve_attack_shares = { lf: 30, rf: 40 }; // rf is not in libero_replacements (['lf'])
|
|
153
|
-
const dto = tacticsColumnsToApiDto(model);
|
|
154
|
-
expect(dto.serveAttackShares).toEqual({ lf: 30 });
|
|
155
|
-
});
|
|
156
|
-
it('leaves serveAttackShares undefined when the column is empty', () => {
|
|
157
|
-
const dto = tacticsColumnsToApiDto(makeTactics([]));
|
|
158
|
-
expect(dto.serveAttackShares).toBeUndefined();
|
|
159
|
-
});
|
|
160
144
|
});
|
|
161
145
|
describe('per-set tactics — service <-> row round-trip', () => {
|
|
162
146
|
const country = makeCountry();
|
|
@@ -174,7 +158,7 @@ describe('per-set tactics — service <-> row round-trip', () => {
|
|
|
174
158
|
{ rotationSystem: RotationSystemEnum.FIVE_ONE, designatedSetters: [p1] },
|
|
175
159
|
{ rotationSystem: RotationSystemEnum.SIX_ZERO, designatedSetters: [] }
|
|
176
160
|
],
|
|
177
|
-
offensivePreferenceSets: [[{ rotation: 1,
|
|
161
|
+
offensivePreferenceSets: [[{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' } }]]
|
|
178
162
|
});
|
|
179
163
|
it('transformFromTactics writes the per-set overrides as id-based jsonb columns', () => {
|
|
180
164
|
const attrs = transformFromTactics(tactics, 'team-1');
|
|
@@ -182,7 +166,7 @@ describe('per-set tactics — service <-> row round-trip', () => {
|
|
|
182
166
|
{ rotationSystem: '5-1', designatedSetters: [p1.id] },
|
|
183
167
|
{ rotationSystem: '6-0', designatedSetters: [] }
|
|
184
168
|
]);
|
|
185
|
-
expect(attrs.offensive_preference_sets).toEqual([[{ rotation: 1,
|
|
169
|
+
expect(attrs.offensive_preference_sets).toEqual([[{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' } }]]);
|
|
186
170
|
});
|
|
187
171
|
it('transformToTactics resolves the stored ids back to roster players', () => {
|
|
188
172
|
const attrs = transformFromTactics(tactics, 'team-1');
|
|
@@ -190,7 +174,7 @@ describe('per-set tactics — service <-> row round-trip', () => {
|
|
|
190
174
|
expect(back.systemSets?.[0].rotationSystem).toBe(RotationSystemEnum.FIVE_ONE);
|
|
191
175
|
expect(back.systemSets?.[0].designatedSetters[0].id).toBe(p1.id);
|
|
192
176
|
expect(back.systemSets?.[1].designatedSetters).toEqual([]);
|
|
193
|
-
expect(back.offensivePreferenceSets?.[0][0].
|
|
177
|
+
expect(back.offensivePreferenceSets?.[0][0].priorities).toEqual({ [p2.id]: 'HIGH', [p3.id]: 'MID' });
|
|
194
178
|
});
|
|
195
179
|
it('omits the per-set columns entirely for an all-sets config', () => {
|
|
196
180
|
const flat = Tactics.create({
|
|
@@ -204,27 +188,6 @@ describe('per-set tactics — service <-> row round-trip', () => {
|
|
|
204
188
|
expect(back.systemSets).toBeUndefined();
|
|
205
189
|
expect(back.offensivePreferenceSets).toBeUndefined();
|
|
206
190
|
});
|
|
207
|
-
it('round-trips serve attack shares keyed by a libero replacement', () => {
|
|
208
|
-
const withServe = Tactics.create({
|
|
209
|
-
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [] },
|
|
210
|
-
liberoReplacements: [p5],
|
|
211
|
-
serveAttackShares: { [p5.id]: 35 }
|
|
212
|
-
});
|
|
213
|
-
const attrs = transformFromTactics(withServe, 'team-1');
|
|
214
|
-
expect(attrs.serve_attack_shares).toEqual({ [p5.id]: 35 });
|
|
215
|
-
const back = transformToTactics(attrs, roster);
|
|
216
|
-
expect(back.serveAttackShares).toEqual({ [p5.id]: 35 });
|
|
217
|
-
});
|
|
218
|
-
it('drops a stale serve attack share key on load (lenient heal, no crash)', () => {
|
|
219
|
-
const attrs = transformFromTactics(Tactics.create({
|
|
220
|
-
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [] },
|
|
221
|
-
liberoReplacements: [p5],
|
|
222
|
-
serveAttackShares: { [p5.id]: 35 }
|
|
223
|
-
}), 'team-1');
|
|
224
|
-
attrs.libero_replacements = [];
|
|
225
|
-
const back = transformToTactics(attrs, roster);
|
|
226
|
-
expect(back.serveAttackShares).toEqual({});
|
|
227
|
-
});
|
|
228
191
|
it('round-trips base positions (coords + reception participation)', () => {
|
|
229
192
|
const config = {
|
|
230
193
|
coords: { RECEIVE: { 1: { 5: { d: 5.5, r: -3 }, 6: { d: 6.5, r: 0 } } }, DEFENCE: { 3: { 2: { d: 0.9, r: 3 } } } },
|
|
@@ -253,11 +216,11 @@ describe('per-set tactics — service <-> row round-trip', () => {
|
|
|
253
216
|
const withTempos = Tactics.create({
|
|
254
217
|
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [] },
|
|
255
218
|
liberoReplacements: [],
|
|
256
|
-
offensivePreferences: [{ rotation: 1,
|
|
219
|
+
offensivePreferences: [{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' }, tempos: { [p2.id]: 'FAST', [p3.id]: 'HIGH' } }]
|
|
257
220
|
});
|
|
258
221
|
const attrs = transformFromTactics(withTempos, 'team-1');
|
|
259
222
|
expect(attrs.offensive_preferences).toEqual([
|
|
260
|
-
{ rotation: 1,
|
|
223
|
+
{ rotation: 1, priorities: { [p2.id]: 'HIGH', [p3.id]: 'MID' }, tempos: { [p2.id]: 'FAST', [p3.id]: 'HIGH' } }
|
|
261
224
|
]);
|
|
262
225
|
const back = transformToTactics(attrs, roster);
|
|
263
226
|
expect(back.offensivePreferences[0].tempos).toEqual({ [p2.id]: 'FAST', [p3.id]: 'HIGH' });
|
|
@@ -7,6 +7,7 @@ export interface BaseCoord {
|
|
|
7
7
|
export interface BaseConfig {
|
|
8
8
|
readonly coords: Record<string, Record<string, Record<string, BaseCoord>>>;
|
|
9
9
|
readonly receive: Record<string, Record<string, boolean>>;
|
|
10
|
+
readonly receiveByPlayer?: Record<string, Record<string, boolean>>;
|
|
10
11
|
readonly blocking?: Record<string, Record<string, Record<string, boolean>>>;
|
|
11
12
|
readonly attackContact?: Record<string, Record<string, BaseCoord>>;
|
|
12
13
|
}
|
|
@@ -3,6 +3,7 @@ export * from './team-generator';
|
|
|
3
3
|
export * from './formation';
|
|
4
4
|
export * from './tactics';
|
|
5
5
|
export * from './base-config';
|
|
6
|
+
export * from './attack-priority';
|
|
6
7
|
export * from './default-base-config';
|
|
7
8
|
export * from './receive-overlap';
|
|
8
9
|
export * from './team-name';
|
|
@@ -3,6 +3,7 @@ export * from './team-generator';
|
|
|
3
3
|
export * from './formation';
|
|
4
4
|
export * from './tactics';
|
|
5
5
|
export * from './base-config';
|
|
6
|
+
export * from './attack-priority';
|
|
6
7
|
export * from './default-base-config';
|
|
7
8
|
export * from './receive-overlap';
|
|
8
9
|
export * from './team-name';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { AttackPriority } from './attack-priority';
|
|
1
2
|
export type TempoPreference = 'FAST' | 'HIGH';
|
|
2
3
|
export interface OffensivePreference {
|
|
3
4
|
readonly rotation: number;
|
|
4
|
-
readonly
|
|
5
|
+
readonly priorities: Record<string, AttackPriority>;
|
|
5
6
|
readonly tempos?: Record<string, TempoPreference>;
|
|
6
7
|
}
|
|
@@ -261,23 +261,32 @@ export declare const TacticsInputSchema: z.ZodObject<{
|
|
|
261
261
|
designatedSetters: z.ZodDefault<z.ZodArray<z.ZodCustom<Player, Player>>>;
|
|
262
262
|
offensivePreferences: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
263
263
|
rotation: z.ZodNumber;
|
|
264
|
-
|
|
264
|
+
priorities: z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
265
|
+
HIGH: "HIGH";
|
|
266
|
+
MID: "MID";
|
|
267
|
+
LOW: "LOW";
|
|
268
|
+
NONE: "NONE";
|
|
269
|
+
}>>;
|
|
265
270
|
tempos: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
266
|
-
FAST: "FAST";
|
|
267
271
|
HIGH: "HIGH";
|
|
272
|
+
FAST: "FAST";
|
|
268
273
|
}>>>;
|
|
269
274
|
}, z.core.$strip>>>;
|
|
270
|
-
serveAttackShares: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
271
275
|
systemSets: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
272
276
|
rotationSystem: z.ZodEnum<typeof RotationSystemEnum>;
|
|
273
277
|
designatedSetters: z.ZodArray<z.ZodCustom<Player, Player>>;
|
|
274
278
|
}, z.core.$strip>>>;
|
|
275
279
|
offensivePreferenceSets: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodObject<{
|
|
276
280
|
rotation: z.ZodNumber;
|
|
277
|
-
|
|
281
|
+
priorities: z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
282
|
+
HIGH: "HIGH";
|
|
283
|
+
MID: "MID";
|
|
284
|
+
LOW: "LOW";
|
|
285
|
+
NONE: "NONE";
|
|
286
|
+
}>>;
|
|
278
287
|
tempos: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodEnum<{
|
|
279
|
-
FAST: "FAST";
|
|
280
288
|
HIGH: "HIGH";
|
|
289
|
+
FAST: "FAST";
|
|
281
290
|
}>>>;
|
|
282
291
|
}, z.core.$strip>>>>;
|
|
283
292
|
blockingPreferences: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -304,6 +313,7 @@ export declare const TacticsInputSchema: z.ZodObject<{
|
|
|
304
313
|
r: z.ZodNumber;
|
|
305
314
|
}, z.core.$strip>>>>;
|
|
306
315
|
receive: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodBoolean>>;
|
|
316
|
+
receiveByPlayer: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodBoolean>>>;
|
|
307
317
|
blocking: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodBoolean>>>>;
|
|
308
318
|
attackContact: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
309
319
|
d: z.ZodNumber;
|