volleyballsimtypes 0.0.505 → 0.0.506
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 +2 -2
- package/dist/cjs/src/api/tactics-player-refs.js +2 -2
- package/dist/cjs/src/data/init-models.js +4 -0
- package/dist/cjs/src/data/models/base-position-preset.d.ts +22 -0
- package/dist/cjs/src/data/models/base-position-preset.js +54 -0
- package/dist/cjs/src/data/models/index.d.ts +1 -0
- package/dist/cjs/src/data/models/index.js +1 -0
- package/dist/cjs/src/data/models/tactics.d.ts +2 -2
- package/dist/cjs/src/data/transformers/tactics.test.js +10 -10
- package/dist/cjs/src/service/competition/competition-rewards.d.ts +20 -0
- package/dist/cjs/src/service/competition/competition-rewards.js +47 -0
- package/dist/cjs/src/service/competition/competition-rewards.test.d.ts +1 -0
- package/dist/cjs/src/service/competition/competition-rewards.test.js +32 -0
- package/dist/cjs/src/service/competition/index.d.ts +2 -0
- package/dist/cjs/src/service/competition/index.js +2 -0
- package/dist/cjs/src/service/competition/league-rewards.d.ts +21 -0
- package/dist/cjs/src/service/competition/league-rewards.js +58 -0
- package/dist/cjs/src/service/competition/league-rewards.test.d.ts +1 -0
- package/dist/cjs/src/service/competition/league-rewards.test.js +50 -0
- package/dist/cjs/src/service/team/blocking-preference.d.ts +3 -1
- package/dist/cjs/src/service/team/blocking-preference.js +2 -1
- package/dist/cjs/src/service/team/default-base-config.d.ts +4 -0
- package/dist/cjs/src/service/team/default-base-config.js +128 -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/schemas/tactics.z.d.ts +10 -2
- package/dist/cjs/src/service/team/schemas/tactics.z.js +13 -4
- package/dist/cjs/src/service/team/schemas/tactics.z.test.js +29 -16
- package/dist/cjs/src/service/team/schemas/team.z.d.ts +10 -2
- package/dist/cjs/src/service/team/team-generator.js +6 -1
- package/dist/esm/src/api/index.d.ts +2 -2
- package/dist/esm/src/api/tactics-player-refs.js +2 -2
- package/dist/esm/src/data/init-models.js +5 -1
- package/dist/esm/src/data/models/base-position-preset.d.ts +22 -0
- package/dist/esm/src/data/models/base-position-preset.js +50 -0
- package/dist/esm/src/data/models/index.d.ts +1 -0
- package/dist/esm/src/data/models/index.js +1 -0
- package/dist/esm/src/data/models/tactics.d.ts +2 -2
- package/dist/esm/src/data/transformers/tactics.test.js +10 -10
- package/dist/esm/src/service/competition/competition-rewards.d.ts +20 -0
- package/dist/esm/src/service/competition/competition-rewards.js +43 -0
- package/dist/esm/src/service/competition/competition-rewards.test.d.ts +1 -0
- package/dist/esm/src/service/competition/competition-rewards.test.js +30 -0
- package/dist/esm/src/service/competition/index.d.ts +2 -0
- package/dist/esm/src/service/competition/index.js +2 -0
- package/dist/esm/src/service/competition/league-rewards.d.ts +21 -0
- package/dist/esm/src/service/competition/league-rewards.js +53 -0
- package/dist/esm/src/service/competition/league-rewards.test.d.ts +1 -0
- package/dist/esm/src/service/competition/league-rewards.test.js +48 -0
- package/dist/esm/src/service/team/blocking-preference.d.ts +3 -1
- package/dist/esm/src/service/team/blocking-preference.js +1 -0
- package/dist/esm/src/service/team/default-base-config.d.ts +4 -0
- package/dist/esm/src/service/team/default-base-config.js +124 -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/schemas/tactics.z.d.ts +10 -2
- package/dist/esm/src/service/team/schemas/tactics.z.js +13 -4
- package/dist/esm/src/service/team/schemas/tactics.z.test.js +29 -16
- package/dist/esm/src/service/team/schemas/team.z.d.ts +10 -2
- package/dist/esm/src/service/team/team-generator.js +6 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BaseConfig, BoxScore, DataProps, DeclineStatus, Division as _Division, League as _League, Match as _Match, MatchSet as _MatchSet, Player as _Player, PlayerPosition, Qualifier as _Qualifier, QualifierMatch as _QualifierMatch, Rally as _Rally, RallyEvent as _RallyEvent, PointBreakdown, RallyMetrics, Season as _Season, Standing as _Standing, Team as _Team, Tournament as _Tournament, TournamentMatch as _TournamentMatch, National as _National, NationalMatch as _NationalMatch, Country as _Country, BlockingAssignment, CourtPosition, ConditionLogic, EnergyBand, MatchForfeitType, PerformanceStats, PinchCondition, RotationSystemEnum, SubBackMode, SubBand } from '../service';
|
|
1
|
+
import { BaseConfig, BoxScore, DataProps, DeclineStatus, Division as _Division, League as _League, Match as _Match, MatchSet as _MatchSet, Player as _Player, PlayerPosition, Qualifier as _Qualifier, QualifierMatch as _QualifierMatch, Rally as _Rally, RallyEvent as _RallyEvent, PointBreakdown, RallyMetrics, Season as _Season, Standing as _Standing, Team as _Team, Tournament as _Tournament, TournamentMatch as _TournamentMatch, National as _National, NationalMatch as _NationalMatch, Country as _Country, BlockingAssignment, DefenceFormation, CourtPosition, ConditionLogic, EnergyBand, MatchForfeitType, PerformanceStats, PinchCondition, RotationSystemEnum, SubBackMode, SubBand } from '../service';
|
|
2
2
|
export * from './tactics-player-refs';
|
|
3
3
|
export type Rally = DataProps<_Rally> & {
|
|
4
4
|
homePlayerPosition: PlayerPosition[];
|
|
@@ -102,7 +102,7 @@ export interface ApiOffensivePreference {
|
|
|
102
102
|
}
|
|
103
103
|
export interface ApiBlockingPreference {
|
|
104
104
|
rotation: number;
|
|
105
|
-
targets: Record<string, BlockingAssignment
|
|
105
|
+
targets: Record<DefenceFormation, Record<string, BlockingAssignment>>;
|
|
106
106
|
}
|
|
107
107
|
export interface ApiSystemSet {
|
|
108
108
|
rotationSystem: RotationSystemEnum;
|
|
@@ -29,8 +29,8 @@ function collectTacticsPlayerIds(config) {
|
|
|
29
29
|
...((config.offensivePreferences ?? []).flatMap(p => Object.keys(p.weights))),
|
|
30
30
|
...((config.systemSets ?? []).flatMap(s => s.designatedSetters)),
|
|
31
31
|
...((config.offensivePreferenceSets ?? []).flat().flatMap(p => Object.keys(p.weights))),
|
|
32
|
-
...((config.blockingPreferences ?? []).flatMap(p => Object.
|
|
33
|
-
...((config.blockingPreferenceSets ?? []).flat().flatMap(p => Object.
|
|
32
|
+
...((config.blockingPreferences ?? []).flatMap(p => Object.values(p.targets).flatMap(m => Object.keys(m ?? {})))),
|
|
33
|
+
...((config.blockingPreferenceSets ?? []).flat().flatMap(p => Object.values(p.targets).flatMap(m => Object.keys(m ?? {})))),
|
|
34
34
|
// Injury replacements reference reserves (roster players outside the lineup); roster membership is the only
|
|
35
35
|
// player check possible here (the schema enforces the bench/reserve role rules).
|
|
36
36
|
...((config.injuryReplacements ?? []).flatMap(ir => [ir.starterId, ir.replacementId, ir.benchBackfillId])),
|
|
@@ -27,6 +27,7 @@ function initModels(sequelize) {
|
|
|
27
27
|
const Wishlist = models_1.WishlistModel.initModel(sequelize);
|
|
28
28
|
const UserSettings = models_1.UserSettingsModel.initModel(sequelize);
|
|
29
29
|
const UserDeviceToken = models_1.UserDeviceTokenModel.initModel(sequelize);
|
|
30
|
+
const BasePositionPreset = models_1.BasePositionPresetModel.initModel(sequelize);
|
|
30
31
|
const Notification = models_1.NotificationModel.initModel(sequelize);
|
|
31
32
|
const AuthIdentity = models_1.AuthIdentityModel.initModel(sequelize);
|
|
32
33
|
const AuthSession = models_1.AuthSessionModel.initModel(sequelize);
|
|
@@ -75,8 +76,10 @@ function initModels(sequelize) {
|
|
|
75
76
|
AuthUser.hasOne(Wishlist, { as: 'Wishlist', foreignKey: 'user_id' });
|
|
76
77
|
AuthUser.hasOne(UserSettings, { as: 'UserSettings', foreignKey: 'user_id' });
|
|
77
78
|
AuthUser.hasMany(UserDeviceToken, { as: 'UserDeviceTokens', foreignKey: 'user_id' });
|
|
79
|
+
AuthUser.hasMany(BasePositionPreset, { as: 'BasePositionPresets', foreignKey: 'user_id' });
|
|
78
80
|
AuthUser.hasMany(Notification, { as: 'Notifications', foreignKey: 'user_id' });
|
|
79
81
|
UserDeviceToken.belongsTo(AuthUser, { as: 'user', foreignKey: 'user_id' });
|
|
82
|
+
BasePositionPreset.belongsTo(AuthUser, { as: 'user', foreignKey: 'user_id' });
|
|
80
83
|
Notification.belongsTo(AuthUser, { as: 'user', foreignKey: 'user_id' });
|
|
81
84
|
AuthUser.hasMany(GachaPullHistory, { as: 'GachaPullHistory', foreignKey: 'user_id' });
|
|
82
85
|
AuthUser.hasMany(UserPullGrant, { as: 'UserPullGrants', foreignKey: 'user_id' });
|
|
@@ -354,6 +357,7 @@ function initModels(sequelize) {
|
|
|
354
357
|
Wishlist,
|
|
355
358
|
UserSettings,
|
|
356
359
|
UserDeviceToken,
|
|
360
|
+
BasePositionPreset,
|
|
357
361
|
Notification,
|
|
358
362
|
Coach,
|
|
359
363
|
Scout,
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as Sequelize from 'sequelize';
|
|
2
|
+
import { Model, Optional } from 'sequelize';
|
|
3
|
+
import { BaseConfig } from '../../service';
|
|
4
|
+
export interface BasePositionPresetAttributes {
|
|
5
|
+
preset_id: string;
|
|
6
|
+
user_id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
config: BaseConfig;
|
|
9
|
+
created_at?: Date;
|
|
10
|
+
}
|
|
11
|
+
export type BasePositionPresetPk = 'preset_id';
|
|
12
|
+
export type BasePositionPresetId = BasePositionPresetModel[BasePositionPresetPk];
|
|
13
|
+
export type BasePositionPresetOptionalAttributes = 'preset_id' | 'created_at';
|
|
14
|
+
export type BasePositionPresetCreationAttributes = Optional<BasePositionPresetAttributes, BasePositionPresetOptionalAttributes>;
|
|
15
|
+
export declare class BasePositionPresetModel extends Model<BasePositionPresetAttributes, BasePositionPresetCreationAttributes> implements BasePositionPresetAttributes {
|
|
16
|
+
preset_id: string;
|
|
17
|
+
user_id: string;
|
|
18
|
+
name: string;
|
|
19
|
+
config: BaseConfig;
|
|
20
|
+
created_at?: Date;
|
|
21
|
+
static initModel(sequelize: Sequelize.Sequelize): typeof BasePositionPresetModel;
|
|
22
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BasePositionPresetModel = void 0;
|
|
4
|
+
const sequelize_1 = require("sequelize");
|
|
5
|
+
class BasePositionPresetModel extends sequelize_1.Model {
|
|
6
|
+
static initModel(sequelize) {
|
|
7
|
+
return BasePositionPresetModel.init({
|
|
8
|
+
preset_id: {
|
|
9
|
+
type: sequelize_1.DataTypes.UUID,
|
|
10
|
+
allowNull: false,
|
|
11
|
+
primaryKey: true,
|
|
12
|
+
defaultValue: sequelize_1.DataTypes.UUIDV4
|
|
13
|
+
},
|
|
14
|
+
user_id: {
|
|
15
|
+
type: sequelize_1.DataTypes.UUID,
|
|
16
|
+
allowNull: false,
|
|
17
|
+
references: {
|
|
18
|
+
model: 'AuthUser',
|
|
19
|
+
key: 'user_id'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
name: {
|
|
23
|
+
type: sequelize_1.DataTypes.STRING,
|
|
24
|
+
allowNull: false
|
|
25
|
+
},
|
|
26
|
+
config: {
|
|
27
|
+
type: sequelize_1.DataTypes.JSONB,
|
|
28
|
+
allowNull: false
|
|
29
|
+
},
|
|
30
|
+
created_at: {
|
|
31
|
+
type: sequelize_1.DataTypes.DATE,
|
|
32
|
+
allowNull: false,
|
|
33
|
+
defaultValue: sequelize_1.DataTypes.NOW
|
|
34
|
+
}
|
|
35
|
+
}, {
|
|
36
|
+
sequelize,
|
|
37
|
+
tableName: 'BasePositionPreset',
|
|
38
|
+
schema: 'public',
|
|
39
|
+
timestamps: false,
|
|
40
|
+
indexes: [
|
|
41
|
+
{
|
|
42
|
+
name: 'BasePositionPreset_pk',
|
|
43
|
+
unique: true,
|
|
44
|
+
fields: [{ name: 'preset_id' }]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'BasePositionPreset_user_id_idx',
|
|
48
|
+
fields: [{ name: 'user_id' }]
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
exports.BasePositionPresetModel = BasePositionPresetModel;
|
|
@@ -38,6 +38,7 @@ export * from './team';
|
|
|
38
38
|
export * from './team-replacement';
|
|
39
39
|
export * from './tactics';
|
|
40
40
|
export * from './lineup-preset';
|
|
41
|
+
export * from './base-position-preset';
|
|
41
42
|
export * from './event';
|
|
42
43
|
export * from './event-competition';
|
|
43
44
|
export * from './event-bot-team';
|
|
@@ -54,6 +54,7 @@ __exportStar(require("./team"), exports);
|
|
|
54
54
|
__exportStar(require("./team-replacement"), exports);
|
|
55
55
|
__exportStar(require("./tactics"), exports);
|
|
56
56
|
__exportStar(require("./lineup-preset"), exports);
|
|
57
|
+
__exportStar(require("./base-position-preset"), exports);
|
|
57
58
|
__exportStar(require("./event"), exports);
|
|
58
59
|
__exportStar(require("./event-competition"), exports);
|
|
59
60
|
__exportStar(require("./event-bot-team"), exports);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as Sequelize from 'sequelize';
|
|
2
2
|
import { Model, Optional } from 'sequelize';
|
|
3
3
|
import { PlayerId, TeamId, TeamModel } from '.';
|
|
4
|
-
import { BaseConfig, BlockingAssignment, ConditionLogic, CourtPosition, EnergyBand, PinchCondition, RotationSystemEnum, SubBackMode, SubBand, SubMode } from '../../service';
|
|
4
|
+
import { BaseConfig, BlockingAssignment, ConditionLogic, CourtPosition, DefenceFormation, EnergyBand, PinchCondition, RotationSystemEnum, SubBackMode, SubBand, SubMode } from '../../service';
|
|
5
5
|
export interface TacticsLineupAttributes {
|
|
6
6
|
[CourtPosition.LIBERO_ZONE]?: PlayerId;
|
|
7
7
|
[CourtPosition.LEFT_BACK]: PlayerId;
|
|
@@ -36,7 +36,7 @@ export interface OffensivePreferenceAttributes {
|
|
|
36
36
|
}
|
|
37
37
|
export interface BlockingPreferenceAttributes {
|
|
38
38
|
rotation: number;
|
|
39
|
-
targets: Record<PlayerId, BlockingAssignment
|
|
39
|
+
targets: Record<DefenceFormation, Record<PlayerId, BlockingAssignment>>;
|
|
40
40
|
}
|
|
41
41
|
export interface SystemSetAttributes {
|
|
42
42
|
rotationSystem: RotationSystemEnum;
|
|
@@ -264,18 +264,18 @@ function makeTactics(designatedSubs) {
|
|
|
264
264
|
const back = (0, tactics_1.transformToTactics)(attrs, roster);
|
|
265
265
|
(0, globals_1.expect)(back.offensivePreferences[0].tempos).toEqual({ [p2.id]: 'FAST', [p3.id]: 'HIGH' });
|
|
266
266
|
});
|
|
267
|
-
(0, globals_1.it)('round-trips blocking preferences as id-keyed function maps', () => {
|
|
267
|
+
(0, globals_1.it)('round-trips blocking preferences as per-defence-side id-keyed function maps', () => {
|
|
268
268
|
const withBlocking = service_1.Tactics.create({
|
|
269
269
|
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [] },
|
|
270
270
|
liberoReplacements: [],
|
|
271
|
-
blockingPreferences: [{ rotation: 1, targets: { [p4.id]: service_1.RoleEnum.OUTSIDE_HITTER, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } }]
|
|
271
|
+
blockingPreferences: [{ rotation: 1, targets: { DEF_L: { [p4.id]: service_1.RoleEnum.OUTSIDE_HITTER }, DEF_R: { [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } } }]
|
|
272
272
|
});
|
|
273
273
|
const attrs = (0, tactics_1.transformFromTactics)(withBlocking, 'team-1');
|
|
274
274
|
(0, globals_1.expect)(attrs.blocking_preferences).toEqual([
|
|
275
|
-
{ rotation: 1, targets: { [p4.id]: service_1.RoleEnum.OUTSIDE_HITTER, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } }
|
|
275
|
+
{ rotation: 1, targets: { DEF_L: { [p4.id]: service_1.RoleEnum.OUTSIDE_HITTER }, DEF_M: {}, DEF_R: { [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } } }
|
|
276
276
|
]);
|
|
277
277
|
const back = (0, tactics_1.transformToTactics)(attrs, roster);
|
|
278
|
-
(0, globals_1.expect)(back.blockingPreferences[0].targets).toEqual({ [p4.id]: service_1.RoleEnum.OUTSIDE_HITTER, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER });
|
|
278
|
+
(0, globals_1.expect)(back.blockingPreferences[0].targets).toEqual({ DEF_L: { [p4.id]: service_1.RoleEnum.OUTSIDE_HITTER }, DEF_M: {}, DEF_R: { [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } });
|
|
279
279
|
});
|
|
280
280
|
// NO_BLOCK rides in the same targets map as a commit assignment, so the transformers copy it wholesale with no
|
|
281
281
|
// mapping code. This pins that: the sentinel must survive the row round-trip verbatim, mixed with a commit, and
|
|
@@ -284,17 +284,17 @@ function makeTactics(designatedSubs) {
|
|
|
284
284
|
const withNoBlock = service_1.Tactics.create({
|
|
285
285
|
lineup: { 4: p4, 3: p3, 2: p2, 5: p5, 6: p6, 1: p1, bench: [] },
|
|
286
286
|
liberoReplacements: [],
|
|
287
|
-
blockingPreferences: [{ rotation: 1, targets: { [p4.id]: service_1.NO_BLOCK, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } }],
|
|
288
|
-
blockingPreferenceSets: [[{ rotation: 2, targets: { [p2.id]: service_1.NO_BLOCK } }]]
|
|
287
|
+
blockingPreferences: [{ rotation: 1, targets: { DEF_M: { [p4.id]: service_1.NO_BLOCK, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } } }],
|
|
288
|
+
blockingPreferenceSets: [[{ rotation: 2, targets: { DEF_L: { [p2.id]: service_1.NO_BLOCK } } }]]
|
|
289
289
|
});
|
|
290
290
|
const attrs = (0, tactics_1.transformFromTactics)(withNoBlock, 'team-1');
|
|
291
291
|
(0, globals_1.expect)(attrs.blocking_preferences).toEqual([
|
|
292
|
-
{ rotation: 1, targets: { [p4.id]: service_1.NO_BLOCK, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER } }
|
|
292
|
+
{ rotation: 1, targets: { DEF_L: {}, DEF_M: { [p4.id]: service_1.NO_BLOCK, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER }, DEF_R: {} } }
|
|
293
293
|
]);
|
|
294
|
-
(0, globals_1.expect)(attrs.blocking_preference_sets).toEqual([[{ rotation: 2, targets: { [p2.id]: service_1.NO_BLOCK } }]]);
|
|
294
|
+
(0, globals_1.expect)(attrs.blocking_preference_sets).toEqual([[{ rotation: 2, targets: { DEF_L: { [p2.id]: service_1.NO_BLOCK }, DEF_M: {}, DEF_R: {} } }]]);
|
|
295
295
|
const back = (0, tactics_1.transformToTactics)(attrs, roster);
|
|
296
|
-
(0, globals_1.expect)(back.blockingPreferences[0].targets).toEqual({ [p4.id]: service_1.NO_BLOCK, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER });
|
|
297
|
-
(0, globals_1.expect)(back.blockingPreferenceSets?.[0][0].targets).toEqual({ [p2.id]: service_1.NO_BLOCK });
|
|
296
|
+
(0, globals_1.expect)(back.blockingPreferences[0].targets).toEqual({ DEF_L: {}, DEF_M: { [p4.id]: service_1.NO_BLOCK, [p3.id]: service_1.RoleEnum.MIDDLE_BLOCKER }, DEF_R: {} });
|
|
297
|
+
(0, globals_1.expect)(back.blockingPreferenceSets?.[0][0].targets).toEqual({ DEF_L: { [p2.id]: service_1.NO_BLOCK }, DEF_M: {}, DEF_R: {} });
|
|
298
298
|
});
|
|
299
299
|
});
|
|
300
300
|
(0, globals_1.describe)('libero injuries — service <-> row round-trip + lenient heal', () => {
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type CompetitionRewardKind = 'REGIONAL' | 'NATIONAL' | 'WCC';
|
|
2
|
+
export interface CompetitionRewardRow {
|
|
3
|
+
/** Best final position that still earns this row: the "Top N" band. */
|
|
4
|
+
readonly maxPosition: number;
|
|
5
|
+
/** Coins awarded by this row alone (the increment, not the running total). */
|
|
6
|
+
readonly coins: number;
|
|
7
|
+
/** Recruit-reward pulls awarded by this row alone (the competition's own pull type). */
|
|
8
|
+
readonly recruits: number;
|
|
9
|
+
}
|
|
10
|
+
/** Per-competition bands, widest band first (the order the docs list them, with a growing cumulative total). */
|
|
11
|
+
export declare const COMPETITION_REWARDS: Readonly<Record<CompetitionRewardKind, readonly CompetitionRewardRow[]>>;
|
|
12
|
+
export interface CompetitionPayout {
|
|
13
|
+
readonly coins: number;
|
|
14
|
+
readonly recruits: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Everything a finishing position earns in the given competition: the sum of every band that still includes the
|
|
18
|
+
* position (cumulative). Positions past the lowest band earn nothing. `position` is the 1-based final placement.
|
|
19
|
+
*/
|
|
20
|
+
export declare function competitionPayoutFor(kind: CompetitionRewardKind, position: number): CompetitionPayout;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// What the knockout competitions (Regional Cup, National Cup, WCC) pay out by final placement. Owner-defined
|
|
3
|
+
// 2026-08-07. Like the event and league rewards, these are CUMULATIVE: a finish earns its band and every band
|
|
4
|
+
// below it. Each band gives coins and/or "recruit rewards" (the competition's own pull grant: a Regional
|
|
5
|
+
// recruit is a QUALIFIER pull, a National recruit a NATIONAL pull, a WCC recruit a TOURNAMENT pull). Recruit
|
|
6
|
+
// rewards stack, so a champion collects one per qualifying band.
|
|
7
|
+
//
|
|
8
|
+
// One source of truth for two consumers: the simulator grants from it and the UI competition docs render it.
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.COMPETITION_REWARDS = void 0;
|
|
11
|
+
exports.competitionPayoutFor = competitionPayoutFor;
|
|
12
|
+
/** Per-competition bands, widest band first (the order the docs list them, with a growing cumulative total). */
|
|
13
|
+
exports.COMPETITION_REWARDS = {
|
|
14
|
+
REGIONAL: [
|
|
15
|
+
{ maxPosition: 4, coins: 1000, recruits: 0 },
|
|
16
|
+
{ maxPosition: 3, coins: 0, recruits: 1 },
|
|
17
|
+
{ maxPosition: 2, coins: 1000, recruits: 0 },
|
|
18
|
+
{ maxPosition: 1, coins: 500, recruits: 1 }
|
|
19
|
+
],
|
|
20
|
+
NATIONAL: [
|
|
21
|
+
{ maxPosition: 8, coins: 1000, recruits: 0 },
|
|
22
|
+
{ maxPosition: 4, coins: 500, recruits: 1 },
|
|
23
|
+
{ maxPosition: 2, coins: 500, recruits: 0 },
|
|
24
|
+
{ maxPosition: 1, coins: 0, recruits: 1 }
|
|
25
|
+
],
|
|
26
|
+
WCC: [
|
|
27
|
+
{ maxPosition: 4, coins: 1000, recruits: 0 },
|
|
28
|
+
{ maxPosition: 3, coins: 0, recruits: 1 },
|
|
29
|
+
{ maxPosition: 2, coins: 500, recruits: 1 },
|
|
30
|
+
{ maxPosition: 1, coins: 500, recruits: 1 }
|
|
31
|
+
]
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Everything a finishing position earns in the given competition: the sum of every band that still includes the
|
|
35
|
+
* position (cumulative). Positions past the lowest band earn nothing. `position` is the 1-based final placement.
|
|
36
|
+
*/
|
|
37
|
+
function competitionPayoutFor(kind, position) {
|
|
38
|
+
let coins = 0;
|
|
39
|
+
let recruits = 0;
|
|
40
|
+
for (const row of exports.COMPETITION_REWARDS[kind]) {
|
|
41
|
+
if (position <= row.maxPosition) {
|
|
42
|
+
coins += row.coins;
|
|
43
|
+
recruits += row.recruits;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { coins, recruits };
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const globals_1 = require("@jest/globals");
|
|
4
|
+
const competition_rewards_1 = require("./competition-rewards");
|
|
5
|
+
// The cumulative per-position totals the owner specified (2026-08-07): { coins, recruits } a finish earns,
|
|
6
|
+
// summing its band and every band below. Positions past the lowest band earn nothing.
|
|
7
|
+
(0, globals_1.describe)('competitionPayoutFor', () => {
|
|
8
|
+
const CASES = {
|
|
9
|
+
// position: [coins, recruits]
|
|
10
|
+
REGIONAL: { 1: [2500, 2], 2: [2000, 1], 3: [1000, 1], 4: [1000, 0], 5: [0, 0] },
|
|
11
|
+
NATIONAL: { 1: [2000, 2], 2: [2000, 1], 3: [1500, 1], 4: [1500, 1], 5: [1000, 0], 8: [1000, 0], 9: [0, 0] },
|
|
12
|
+
WCC: { 1: [2000, 3], 2: [1500, 2], 3: [1000, 1], 4: [1000, 0], 5: [0, 0] }
|
|
13
|
+
};
|
|
14
|
+
for (const kind of Object.keys(CASES)) {
|
|
15
|
+
(0, globals_1.it)(`matches the owner totals for ${kind}`, () => {
|
|
16
|
+
for (const [pos, [coins, recruits]] of Object.entries(CASES[kind])) {
|
|
17
|
+
(0, globals_1.expect)((0, competition_rewards_1.competitionPayoutFor)(kind, Number(pos))).toEqual({ coins, recruits });
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
(0, globals_1.it)('champion collects one recruit per qualifying band', () => {
|
|
22
|
+
(0, globals_1.expect)((0, competition_rewards_1.competitionPayoutFor)('REGIONAL', 1).recruits).toBe(2);
|
|
23
|
+
(0, globals_1.expect)((0, competition_rewards_1.competitionPayoutFor)('NATIONAL', 1).recruits).toBe(2);
|
|
24
|
+
(0, globals_1.expect)((0, competition_rewards_1.competitionPayoutFor)('WCC', 1).recruits).toBe(3);
|
|
25
|
+
});
|
|
26
|
+
(0, globals_1.it)('champion coin total equals the sum of the band table', () => {
|
|
27
|
+
const sum = (k) => competition_rewards_1.COMPETITION_REWARDS[k].reduce((s, r) => s + r.coins, 0);
|
|
28
|
+
(0, globals_1.expect)((0, competition_rewards_1.competitionPayoutFor)('REGIONAL', 1).coins).toBe(sum('REGIONAL'));
|
|
29
|
+
(0, globals_1.expect)((0, competition_rewards_1.competitionPayoutFor)('NATIONAL', 1).coins).toBe(sum('NATIONAL'));
|
|
30
|
+
(0, globals_1.expect)((0, competition_rewards_1.competitionPayoutFor)('WCC', 1).coins).toBe(sum('WCC'));
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -3,6 +3,8 @@ export * from './season';
|
|
|
3
3
|
export * from './event-schedule';
|
|
4
4
|
export * from './event-draft';
|
|
5
5
|
export * from './event-rewards';
|
|
6
|
+
export * from './league-rewards';
|
|
7
|
+
export * from './competition-rewards';
|
|
6
8
|
export * from './league';
|
|
7
9
|
export * from './division';
|
|
8
10
|
export * from './iteration';
|
|
@@ -19,6 +19,8 @@ __exportStar(require("./season"), exports);
|
|
|
19
19
|
__exportStar(require("./event-schedule"), exports);
|
|
20
20
|
__exportStar(require("./event-draft"), exports);
|
|
21
21
|
__exportStar(require("./event-rewards"), exports);
|
|
22
|
+
__exportStar(require("./league-rewards"), exports);
|
|
23
|
+
__exportStar(require("./competition-rewards"), exports);
|
|
22
24
|
__exportStar(require("./league"), exports);
|
|
23
25
|
__exportStar(require("./division"), exports);
|
|
24
26
|
__exportStar(require("./iteration"), exports);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface LeagueRewardRow {
|
|
2
|
+
/** Best final position that still earns this row: the "Top N" band. */
|
|
3
|
+
readonly maxPosition: number;
|
|
4
|
+
/** Coins awarded by this row alone (the increment, not the running total). */
|
|
5
|
+
readonly coins: number;
|
|
6
|
+
}
|
|
7
|
+
/** Division tiers that get their own reward table. Tier 3 covers "division 3 and lower". */
|
|
8
|
+
export type LeagueRewardTier = 1 | 2 | 3;
|
|
9
|
+
/**
|
|
10
|
+
* Per-tier bands, widest band first (the order the standings doc lists them, with a growing cumulative total).
|
|
11
|
+
* A team earns every row whose band still includes its finishing position, which is what "cumulative" means.
|
|
12
|
+
*/
|
|
13
|
+
export declare const LEAGUE_REWARDS: Readonly<Record<LeagueRewardTier, readonly LeagueRewardRow[]>>;
|
|
14
|
+
/** Clamp any division tier to a reward table: tier 1, tier 2, and tier 3-and-lower share the tier-3 table. */
|
|
15
|
+
export declare function leagueRewardTier(tier: number): LeagueRewardTier;
|
|
16
|
+
/**
|
|
17
|
+
* Coins a finishing position earns in a division of the given tier: the sum of every band that still includes
|
|
18
|
+
* the position (cumulative). Positions past the lowest band earn 0. `position` is the 1-based final standings
|
|
19
|
+
* place.
|
|
20
|
+
*/
|
|
21
|
+
export declare function leaguePayoutFor(tier: number, position: number): number;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// What a league season pays out at the end, by division tier and final standings position. Owner-defined
|
|
3
|
+
// 2026-08-07. Like the event rewards, these are CUMULATIVE: a team collects its own band and every band below
|
|
4
|
+
// it, so first place collects them all. Positions past the lowest band earn nothing.
|
|
5
|
+
//
|
|
6
|
+
// One source of truth for two consumers: the simulator grants from it (assignSeasonPayoutIfMissing) and the UI
|
|
7
|
+
// standings doc renders it.
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.LEAGUE_REWARDS = void 0;
|
|
10
|
+
exports.leagueRewardTier = leagueRewardTier;
|
|
11
|
+
exports.leaguePayoutFor = leaguePayoutFor;
|
|
12
|
+
/**
|
|
13
|
+
* Per-tier bands, widest band first (the order the standings doc lists them, with a growing cumulative total).
|
|
14
|
+
* A team earns every row whose band still includes its finishing position, which is what "cumulative" means.
|
|
15
|
+
*/
|
|
16
|
+
exports.LEAGUE_REWARDS = {
|
|
17
|
+
1: [
|
|
18
|
+
{ maxPosition: 12, coins: 1000 },
|
|
19
|
+
{ maxPosition: 8, coins: 500 },
|
|
20
|
+
{ maxPosition: 4, coins: 500 },
|
|
21
|
+
{ maxPosition: 3, coins: 250 },
|
|
22
|
+
{ maxPosition: 2, coins: 250 },
|
|
23
|
+
{ maxPosition: 1, coins: 500 }
|
|
24
|
+
],
|
|
25
|
+
2: [
|
|
26
|
+
{ maxPosition: 8, coins: 500 },
|
|
27
|
+
{ maxPosition: 4, coins: 500 },
|
|
28
|
+
{ maxPosition: 2, coins: 250 },
|
|
29
|
+
{ maxPosition: 1, coins: 250 }
|
|
30
|
+
],
|
|
31
|
+
3: [
|
|
32
|
+
{ maxPosition: 4, coins: 500 },
|
|
33
|
+
{ maxPosition: 2, coins: 250 },
|
|
34
|
+
{ maxPosition: 1, coins: 250 }
|
|
35
|
+
]
|
|
36
|
+
};
|
|
37
|
+
/** Clamp any division tier to a reward table: tier 1, tier 2, and tier 3-and-lower share the tier-3 table. */
|
|
38
|
+
function leagueRewardTier(tier) {
|
|
39
|
+
const t = Math.trunc(tier);
|
|
40
|
+
if (t <= 1)
|
|
41
|
+
return 1;
|
|
42
|
+
if (t === 2)
|
|
43
|
+
return 2;
|
|
44
|
+
return 3;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Coins a finishing position earns in a division of the given tier: the sum of every band that still includes
|
|
48
|
+
* the position (cumulative). Positions past the lowest band earn 0. `position` is the 1-based final standings
|
|
49
|
+
* place.
|
|
50
|
+
*/
|
|
51
|
+
function leaguePayoutFor(tier, position) {
|
|
52
|
+
let coins = 0;
|
|
53
|
+
for (const row of exports.LEAGUE_REWARDS[leagueRewardTier(tier)]) {
|
|
54
|
+
if (position <= row.maxPosition)
|
|
55
|
+
coins += row.coins;
|
|
56
|
+
}
|
|
57
|
+
return coins;
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const globals_1 = require("@jest/globals");
|
|
4
|
+
const league_rewards_1 = require("./league-rewards");
|
|
5
|
+
// The cumulative per-tier totals the owner specified (2026-08-07). Every entry is the coins a team finishing at
|
|
6
|
+
// that position earns, summing its band and every band below it. Positions past the lowest band earn 0.
|
|
7
|
+
(0, globals_1.describe)('leaguePayoutFor', () => {
|
|
8
|
+
const TIER1 = {
|
|
9
|
+
1: 3000, 2: 2500, 3: 2250, 4: 2000, 5: 1500, 6: 1500, 7: 1500, 8: 1500, 9: 1000, 10: 1000, 11: 1000, 12: 1000, 13: 0, 14: 0, 15: 0, 16: 0
|
|
10
|
+
};
|
|
11
|
+
const TIER2 = {
|
|
12
|
+
1: 1500, 2: 1250, 3: 1000, 4: 1000, 5: 500, 6: 500, 7: 500, 8: 500, 9: 0, 12: 0, 16: 0
|
|
13
|
+
};
|
|
14
|
+
const TIER3 = {
|
|
15
|
+
1: 1000, 2: 750, 3: 500, 4: 500, 5: 0, 8: 0, 16: 0
|
|
16
|
+
};
|
|
17
|
+
(0, globals_1.it)('matches the owner cumulative totals for tier 1', () => {
|
|
18
|
+
for (const [pos, total] of Object.entries(TIER1)) {
|
|
19
|
+
(0, globals_1.expect)((0, league_rewards_1.leaguePayoutFor)(1, Number(pos))).toBe(total);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
(0, globals_1.it)('matches the owner cumulative totals for tier 2', () => {
|
|
23
|
+
for (const [pos, total] of Object.entries(TIER2)) {
|
|
24
|
+
(0, globals_1.expect)((0, league_rewards_1.leaguePayoutFor)(2, Number(pos))).toBe(total);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
(0, globals_1.it)('matches the owner cumulative totals for tier 3', () => {
|
|
28
|
+
for (const [pos, total] of Object.entries(TIER3)) {
|
|
29
|
+
(0, globals_1.expect)((0, league_rewards_1.leaguePayoutFor)(3, Number(pos))).toBe(total);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
(0, globals_1.it)('treats division 3 and lower with the tier-3 table', () => {
|
|
33
|
+
for (const tier of [3, 4, 5, 10]) {
|
|
34
|
+
(0, globals_1.expect)((0, league_rewards_1.leagueRewardTier)(tier)).toBe(3);
|
|
35
|
+
(0, globals_1.expect)((0, league_rewards_1.leaguePayoutFor)(tier, 1)).toBe(1000);
|
|
36
|
+
(0, globals_1.expect)((0, league_rewards_1.leaguePayoutFor)(tier, 4)).toBe(500);
|
|
37
|
+
(0, globals_1.expect)((0, league_rewards_1.leaguePayoutFor)(tier, 5)).toBe(0);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
(0, globals_1.it)('clamps tier 0 or negative to tier 1', () => {
|
|
41
|
+
(0, globals_1.expect)((0, league_rewards_1.leagueRewardTier)(0)).toBe(1);
|
|
42
|
+
(0, globals_1.expect)((0, league_rewards_1.leaguePayoutFor)(0, 1)).toBe(3000);
|
|
43
|
+
});
|
|
44
|
+
(0, globals_1.it)('each tier band table sums to the champion total', () => {
|
|
45
|
+
const sum = (t) => league_rewards_1.LEAGUE_REWARDS[t].reduce((s, r) => s + r.coins, 0);
|
|
46
|
+
(0, globals_1.expect)(sum(1)).toBe(3000);
|
|
47
|
+
(0, globals_1.expect)(sum(2)).toBe(1500);
|
|
48
|
+
(0, globals_1.expect)(sum(3)).toBe(1000);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { LineupFunction } from './lineup-function';
|
|
2
2
|
export declare const NO_BLOCK: "NO_BLOCK";
|
|
3
3
|
export type BlockingAssignment = LineupFunction | typeof NO_BLOCK;
|
|
4
|
+
export type DefenceFormation = 'DEF_L' | 'DEF_M' | 'DEF_R';
|
|
5
|
+
export declare const DEFENCE_FORMATIONS: readonly DefenceFormation[];
|
|
4
6
|
export interface BlockingPreference {
|
|
5
7
|
readonly rotation: number;
|
|
6
|
-
readonly targets: Record<string, BlockingAssignment
|
|
8
|
+
readonly targets: Record<DefenceFormation, Record<string, BlockingAssignment>>;
|
|
7
9
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NO_BLOCK = void 0;
|
|
3
|
+
exports.DEFENCE_FORMATIONS = exports.NO_BLOCK = void 0;
|
|
4
4
|
// A front-row player opted OUT of blocking for this rotation. They never join the wall under any circumstance:
|
|
5
5
|
// not as the lead blocker (the lane's next-nearest front-row player leads instead), not as a side blocker, and
|
|
6
6
|
// no trait can coerce them in -- MOVING_WALL's guaranteed lead hand, its beaten-read hand and its side-joiner
|
|
7
7
|
// roll are all suppressed, as is a dedicated-blocking commit. Sits in the same `targets` map as a commit
|
|
8
8
|
// assignment, so the two are mutually exclusive by construction: a player is reading, committed, or out.
|
|
9
9
|
exports.NO_BLOCK = 'NO_BLOCK';
|
|
10
|
+
exports.DEFENCE_FORMATIONS = ['DEF_L', 'DEF_M', 'DEF_R'];
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { BaseConfig } from './base-config';
|
|
2
|
+
import { RotationSystemEnum } from './rotation-system';
|
|
3
|
+
export declare function defaultReceiveMap(system: RotationSystemEnum): BaseConfig['receive'];
|
|
4
|
+
export declare function defaultBaseConfig(system: RotationSystemEnum): BaseConfig;
|