volleyballsimtypes 0.0.449 → 0.0.452
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/data/transformers/season.js +7 -4
- package/dist/cjs/src/service/event/schemas/block.z.d.ts +8 -0
- package/dist/cjs/src/service/event/schemas/reception.z.d.ts +8 -0
- package/dist/cjs/src/service/event/schemas/serve.z.d.ts +8 -0
- package/dist/cjs/src/service/event/schemas/set.z.d.ts +8 -0
- package/dist/cjs/src/service/event/schemas/spike.z.d.ts +8 -0
- package/dist/cjs/src/service/player/schemas/player.z.d.ts +8 -0
- package/dist/cjs/src/service/player/trait.d.ts +41 -2
- package/dist/cjs/src/service/player/trait.js +49 -1
- package/dist/cjs/src/stat-config/traits.json +74 -0
- package/dist/esm/src/data/transformers/season.js +8 -5
- package/dist/esm/src/service/event/schemas/block.z.d.ts +8 -0
- package/dist/esm/src/service/event/schemas/reception.z.d.ts +8 -0
- package/dist/esm/src/service/event/schemas/serve.z.d.ts +8 -0
- package/dist/esm/src/service/event/schemas/set.z.d.ts +8 -0
- package/dist/esm/src/service/event/schemas/spike.z.d.ts +8 -0
- package/dist/esm/src/service/player/schemas/player.z.d.ts +8 -0
- package/dist/esm/src/service/player/trait.d.ts +41 -2
- package/dist/esm/src/service/player/trait.js +49 -1
- package/dist/esm/src/stat-config/traits.json +74 -0
- package/package.json +1 -1
|
@@ -33,14 +33,17 @@ function transformToAttributes(season) {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
function transformToObject(model) {
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
const teams = (0, _1.sortTeamsByCompetitionIndex)(model.Teams ?? []).map(_1.transformToTeam);
|
|
37
|
+
// One standing per roster team: the persisted CompetitionStandings aggregate where it exists, a zero-stat
|
|
38
|
+
// row otherwise. CompetitionStandings only gains a row once a team plays (the DB trigger fires on match
|
|
39
|
+
// COMPLETE), so mapping it directly dropped un-played teams from the table for the first part of a season.
|
|
40
|
+
const standingByTeam = new Map((model.CompetitionStandings ?? []).map(s => [s.team_id, (0, _1.transformToStanding)(s)]));
|
|
41
|
+
const standings = teams.map(t => standingByTeam.get(t.id) ?? service_1.Standing.create({ teamId: t.id }));
|
|
39
42
|
return service_1.Season.create({
|
|
40
43
|
id: model.competition_id,
|
|
41
44
|
matches: (model.CompetitionMatches ?? []).map((matches) => (0, _1.transformToMatch)(matches.Match)),
|
|
42
45
|
iteration: (0, _1.transformToIteration)(model.Iteration),
|
|
43
|
-
teams
|
|
46
|
+
teams,
|
|
44
47
|
champion: model.CompetitionChampion != null ? (0, _1.transformToTeam)(model.CompetitionChampion.team) : undefined,
|
|
45
48
|
status: model.status,
|
|
46
49
|
divisionId: model.DivisionSeason.division_id,
|
|
@@ -14,6 +14,14 @@ export declare const BlockInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const ReceptionInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const ServeInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const SetInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const SpikeInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -53,6 +53,14 @@ export declare const PlayerInputSchema: z.ZodObject<{
|
|
|
53
53
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
54
54
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
55
55
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
56
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
57
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
58
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
59
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
60
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
61
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
62
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
63
|
+
HUNTER: TraitEnum.HUNTER;
|
|
56
64
|
}>>;
|
|
57
65
|
rarity: z.ZodEnum<{
|
|
58
66
|
COMMON: RarityEnum.COMMON;
|
|
@@ -5,6 +5,7 @@ interface TraitProps {
|
|
|
5
5
|
readonly modifier?: number;
|
|
6
6
|
readonly chance: number;
|
|
7
7
|
readonly roles: Role[];
|
|
8
|
+
readonly maxRarity?: Rarity;
|
|
8
9
|
}
|
|
9
10
|
export declare enum TraitEnum {
|
|
10
11
|
/**
|
|
@@ -45,9 +46,47 @@ export declare enum TraitEnum {
|
|
|
45
46
|
/**
|
|
46
47
|
* Gives the player a chance to perform a perfect reception.
|
|
47
48
|
*/
|
|
48
|
-
DEFENSIVE_SPECIALIST = "DEFENSIVE_SPECIALIST"
|
|
49
|
+
DEFENSIVE_SPECIALIST = "DEFENSIVE_SPECIALIST",
|
|
50
|
+
/**
|
|
51
|
+
* Three good receptions/digs/sets in a row make the next reception/dig/set a guaranteed critical that
|
|
52
|
+
* cannot fail.
|
|
53
|
+
*/
|
|
54
|
+
QUICK_LEARNER = "QUICK_LEARNER",
|
|
55
|
+
/**
|
|
56
|
+
* Each successful attack ramps up the spike, and a kill ramps it more. Starts with a small penalty and
|
|
57
|
+
* resets on an attacking error.
|
|
58
|
+
*/
|
|
59
|
+
MOMENTUM_ADDICT = "MOMENTUM_ADDICT",
|
|
60
|
+
/**
|
|
61
|
+
* A front-row kill demoralizes the opponents who faced it, debuffing them for a few rallies.
|
|
62
|
+
*/
|
|
63
|
+
LOUDMOUTH = "LOUDMOUTH",
|
|
64
|
+
/**
|
|
65
|
+
* When a teammate makes a non-block mistake, that teammate's next action cannot fail.
|
|
66
|
+
*/
|
|
67
|
+
TRUE_LEADER = "TRUE_LEADER",
|
|
68
|
+
/**
|
|
69
|
+
* Reacting to a strong opponent action (block/receive), this player can rise to match it. Limited to
|
|
70
|
+
* Mythic rarity and below.
|
|
71
|
+
*/
|
|
72
|
+
OVERACHIEVER = "OVERACHIEVER",
|
|
73
|
+
/**
|
|
74
|
+
* Opponents who interact with this player's serve or attack spend twice the energy (VIGOROUS is nullified).
|
|
75
|
+
*/
|
|
76
|
+
CRAFTY = "CRAFTY",
|
|
77
|
+
/**
|
|
78
|
+
* When the team loses several points in a row, the whole on-court team gets a buff that grows with the
|
|
79
|
+
* streak and disappears the moment they win a point.
|
|
80
|
+
*/
|
|
81
|
+
TENACIOUS = "TENACIOUS",
|
|
82
|
+
/**
|
|
83
|
+
* Serve trait, rolled before the ambient setter/opposite hunt: a chance to serve a precise target (the
|
|
84
|
+
* setter, opposite, or best back-row attacker, depending on serve type and rotation), bypassing GUARDIAN,
|
|
85
|
+
* with a slight serve bonus and reducing the hunted player's attack involvement that rally.
|
|
86
|
+
*/
|
|
87
|
+
HUNTER = "HUNTER"
|
|
49
88
|
}
|
|
50
|
-
export type Trait = TraitEnum.FLOAT_SERVE | TraitEnum.SURPRISE_ATTACK | TraitEnum.GUARDIAN | TraitEnum.MASTER_MIND | TraitEnum.MOVING_WALL | TraitEnum.MARKSMAN | TraitEnum.METEOR_SERVE | TraitEnum.VIGOROUS | TraitEnum.DEFENSIVE_SPECIALIST;
|
|
89
|
+
export type Trait = TraitEnum.FLOAT_SERVE | TraitEnum.SURPRISE_ATTACK | TraitEnum.GUARDIAN | TraitEnum.MASTER_MIND | TraitEnum.MOVING_WALL | TraitEnum.MARKSMAN | TraitEnum.METEOR_SERVE | TraitEnum.VIGOROUS | TraitEnum.DEFENSIVE_SPECIALIST | TraitEnum.QUICK_LEARNER | TraitEnum.MOMENTUM_ADDICT | TraitEnum.LOUDMOUTH | TraitEnum.TRUE_LEADER | TraitEnum.OVERACHIEVER | TraitEnum.CRAFTY | TraitEnum.TENACIOUS | TraitEnum.HUNTER;
|
|
51
90
|
export declare function assignTraits(roles: Role[], rarity: Rarity, maxTraits?: boolean): Trait[];
|
|
52
91
|
export declare const traitMap: Map<Trait, TraitProps>;
|
|
53
92
|
export {};
|
|
@@ -10,6 +10,14 @@ const node_crypto_1 = require("node:crypto");
|
|
|
10
10
|
const traits_json_1 = __importDefault(require("../../stat-config/traits.json"));
|
|
11
11
|
const utils_1 = require("../utils");
|
|
12
12
|
const traits = traits_json_1.default;
|
|
13
|
+
// Ascending rarity order, used by the maxRarity trait-eligibility gate in assignTraits.
|
|
14
|
+
const RARITY_RANK = {
|
|
15
|
+
[rarity_1.RarityEnum.COMMON]: 0,
|
|
16
|
+
[rarity_1.RarityEnum.RARE]: 1,
|
|
17
|
+
[rarity_1.RarityEnum.LEGENDARY]: 2,
|
|
18
|
+
[rarity_1.RarityEnum.MYTHIC]: 3,
|
|
19
|
+
[rarity_1.RarityEnum.SPECIAL]: 4
|
|
20
|
+
};
|
|
13
21
|
var TraitEnum;
|
|
14
22
|
(function (TraitEnum) {
|
|
15
23
|
/**
|
|
@@ -51,6 +59,44 @@ var TraitEnum;
|
|
|
51
59
|
* Gives the player a chance to perform a perfect reception.
|
|
52
60
|
*/
|
|
53
61
|
TraitEnum["DEFENSIVE_SPECIALIST"] = "DEFENSIVE_SPECIALIST";
|
|
62
|
+
/**
|
|
63
|
+
* Three good receptions/digs/sets in a row make the next reception/dig/set a guaranteed critical that
|
|
64
|
+
* cannot fail.
|
|
65
|
+
*/
|
|
66
|
+
TraitEnum["QUICK_LEARNER"] = "QUICK_LEARNER";
|
|
67
|
+
/**
|
|
68
|
+
* Each successful attack ramps up the spike, and a kill ramps it more. Starts with a small penalty and
|
|
69
|
+
* resets on an attacking error.
|
|
70
|
+
*/
|
|
71
|
+
TraitEnum["MOMENTUM_ADDICT"] = "MOMENTUM_ADDICT";
|
|
72
|
+
/**
|
|
73
|
+
* A front-row kill demoralizes the opponents who faced it, debuffing them for a few rallies.
|
|
74
|
+
*/
|
|
75
|
+
TraitEnum["LOUDMOUTH"] = "LOUDMOUTH";
|
|
76
|
+
/**
|
|
77
|
+
* When a teammate makes a non-block mistake, that teammate's next action cannot fail.
|
|
78
|
+
*/
|
|
79
|
+
TraitEnum["TRUE_LEADER"] = "TRUE_LEADER";
|
|
80
|
+
/**
|
|
81
|
+
* Reacting to a strong opponent action (block/receive), this player can rise to match it. Limited to
|
|
82
|
+
* Mythic rarity and below.
|
|
83
|
+
*/
|
|
84
|
+
TraitEnum["OVERACHIEVER"] = "OVERACHIEVER";
|
|
85
|
+
/**
|
|
86
|
+
* Opponents who interact with this player's serve or attack spend twice the energy (VIGOROUS is nullified).
|
|
87
|
+
*/
|
|
88
|
+
TraitEnum["CRAFTY"] = "CRAFTY";
|
|
89
|
+
/**
|
|
90
|
+
* When the team loses several points in a row, the whole on-court team gets a buff that grows with the
|
|
91
|
+
* streak and disappears the moment they win a point.
|
|
92
|
+
*/
|
|
93
|
+
TraitEnum["TENACIOUS"] = "TENACIOUS";
|
|
94
|
+
/**
|
|
95
|
+
* Serve trait, rolled before the ambient setter/opposite hunt: a chance to serve a precise target (the
|
|
96
|
+
* setter, opposite, or best back-row attacker, depending on serve type and rotation), bypassing GUARDIAN,
|
|
97
|
+
* with a slight serve bonus and reducing the hunted player's attack involvement that rally.
|
|
98
|
+
*/
|
|
99
|
+
TraitEnum["HUNTER"] = "HUNTER";
|
|
54
100
|
})(TraitEnum || (exports.TraitEnum = TraitEnum = {}));
|
|
55
101
|
function assignTraits(roles, rarity, maxTraits) {
|
|
56
102
|
let traitCount;
|
|
@@ -82,7 +128,9 @@ function assignTraits(roles, rarity, maxTraits) {
|
|
|
82
128
|
return [];
|
|
83
129
|
const filteredTraits = traits.filter((trait) => {
|
|
84
130
|
const setA = new Set(trait.roles);
|
|
85
|
-
|
|
131
|
+
const roleMatch = roles.some(el => setA.has(el));
|
|
132
|
+
const rarityOk = trait.maxRarity == null || RARITY_RANK[rarity] <= RARITY_RANK[trait.maxRarity];
|
|
133
|
+
return roleMatch && rarityOk;
|
|
86
134
|
}).map(trait => trait.name);
|
|
87
135
|
return (0, utils_1.shuffle)(filteredTraits).slice(0, traitCount);
|
|
88
136
|
}
|
|
@@ -90,5 +90,79 @@
|
|
|
90
90
|
"OUTSIDE_HITTER",
|
|
91
91
|
"MIDDLE_BLOCKER"
|
|
92
92
|
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "QUICK_LEARNER",
|
|
96
|
+
"chance": 1,
|
|
97
|
+
"roles": [
|
|
98
|
+
"SETTER",
|
|
99
|
+
"LIBERO",
|
|
100
|
+
"OUTSIDE_HITTER"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "MOMENTUM_ADDICT",
|
|
105
|
+
"chance": 1,
|
|
106
|
+
"roles": [
|
|
107
|
+
"OUTSIDE_HITTER",
|
|
108
|
+
"OPPOSITE_HITTER",
|
|
109
|
+
"MIDDLE_BLOCKER"
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "LOUDMOUTH",
|
|
114
|
+
"chance": 0.25,
|
|
115
|
+
"roles": [
|
|
116
|
+
"OUTSIDE_HITTER",
|
|
117
|
+
"OPPOSITE_HITTER",
|
|
118
|
+
"MIDDLE_BLOCKER"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "TRUE_LEADER",
|
|
123
|
+
"chance": 0.3,
|
|
124
|
+
"roles": [
|
|
125
|
+
"SETTER",
|
|
126
|
+
"LIBERO",
|
|
127
|
+
"OUTSIDE_HITTER"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "OVERACHIEVER",
|
|
132
|
+
"chance": 0.2,
|
|
133
|
+
"maxRarity": "MYTHIC",
|
|
134
|
+
"roles": [
|
|
135
|
+
"LIBERO",
|
|
136
|
+
"OUTSIDE_HITTER",
|
|
137
|
+
"MIDDLE_BLOCKER"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "CRAFTY",
|
|
142
|
+
"chance": 0.3,
|
|
143
|
+
"roles": [
|
|
144
|
+
"SETTER",
|
|
145
|
+
"OUTSIDE_HITTER",
|
|
146
|
+
"OPPOSITE_HITTER",
|
|
147
|
+
"MIDDLE_BLOCKER"
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "TENACIOUS",
|
|
152
|
+
"chance": 1,
|
|
153
|
+
"roles": [
|
|
154
|
+
"SETTER",
|
|
155
|
+
"LIBERO",
|
|
156
|
+
"OUTSIDE_HITTER"
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"name": "HUNTER",
|
|
161
|
+
"chance": 0.15,
|
|
162
|
+
"roles": [
|
|
163
|
+
"SETTER",
|
|
164
|
+
"OPPOSITE_HITTER",
|
|
165
|
+
"OUTSIDE_HITTER"
|
|
166
|
+
]
|
|
93
167
|
}
|
|
94
168
|
]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sortTeamsByCompetitionIndex, transformFromSeasonMatch, transformToIteration, transformToMatch, transformToStanding, transformToTeam } from '.';
|
|
2
|
-
import { Season } from '../../service';
|
|
2
|
+
import { Season, Standing } from '../../service';
|
|
3
3
|
function transformToAttributes(season) {
|
|
4
4
|
const matches = (season.matches ?? []).map((match, index) => transformFromSeasonMatch(season.id, match, index));
|
|
5
5
|
const teams = season.teams.map((team, index) => ({
|
|
@@ -29,14 +29,17 @@ function transformToAttributes(season) {
|
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
31
|
function transformToObject(model) {
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
const teams = sortTeamsByCompetitionIndex(model.Teams ?? []).map(transformToTeam);
|
|
33
|
+
// One standing per roster team: the persisted CompetitionStandings aggregate where it exists, a zero-stat
|
|
34
|
+
// row otherwise. CompetitionStandings only gains a row once a team plays (the DB trigger fires on match
|
|
35
|
+
// COMPLETE), so mapping it directly dropped un-played teams from the table for the first part of a season.
|
|
36
|
+
const standingByTeam = new Map((model.CompetitionStandings ?? []).map(s => [s.team_id, transformToStanding(s)]));
|
|
37
|
+
const standings = teams.map(t => standingByTeam.get(t.id) ?? Standing.create({ teamId: t.id }));
|
|
35
38
|
return Season.create({
|
|
36
39
|
id: model.competition_id,
|
|
37
40
|
matches: (model.CompetitionMatches ?? []).map((matches) => transformToMatch(matches.Match)),
|
|
38
41
|
iteration: transformToIteration(model.Iteration),
|
|
39
|
-
teams
|
|
42
|
+
teams,
|
|
40
43
|
champion: model.CompetitionChampion != null ? transformToTeam(model.CompetitionChampion.team) : undefined,
|
|
41
44
|
status: model.status,
|
|
42
45
|
divisionId: model.DivisionSeason.division_id,
|
|
@@ -14,6 +14,14 @@ export declare const BlockInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const ReceptionInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const ServeInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const SetInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -14,6 +14,14 @@ export declare const SpikeInputSchema: z.ZodObject<{
|
|
|
14
14
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
15
15
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
16
16
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
17
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
18
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
19
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
20
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
21
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
22
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
23
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
24
|
+
HUNTER: TraitEnum.HUNTER;
|
|
17
25
|
}>>>;
|
|
18
26
|
failure: z.ZodNumber;
|
|
19
27
|
type: z.ZodNumber;
|
|
@@ -53,6 +53,14 @@ export declare const PlayerInputSchema: z.ZodObject<{
|
|
|
53
53
|
GUARDIAN: TraitEnum.GUARDIAN;
|
|
54
54
|
FLOAT_SERVE: TraitEnum.FLOAT_SERVE;
|
|
55
55
|
DEFENSIVE_SPECIALIST: TraitEnum.DEFENSIVE_SPECIALIST;
|
|
56
|
+
QUICK_LEARNER: TraitEnum.QUICK_LEARNER;
|
|
57
|
+
MOMENTUM_ADDICT: TraitEnum.MOMENTUM_ADDICT;
|
|
58
|
+
LOUDMOUTH: TraitEnum.LOUDMOUTH;
|
|
59
|
+
TRUE_LEADER: TraitEnum.TRUE_LEADER;
|
|
60
|
+
OVERACHIEVER: TraitEnum.OVERACHIEVER;
|
|
61
|
+
CRAFTY: TraitEnum.CRAFTY;
|
|
62
|
+
TENACIOUS: TraitEnum.TENACIOUS;
|
|
63
|
+
HUNTER: TraitEnum.HUNTER;
|
|
56
64
|
}>>;
|
|
57
65
|
rarity: z.ZodEnum<{
|
|
58
66
|
COMMON: RarityEnum.COMMON;
|
|
@@ -5,6 +5,7 @@ interface TraitProps {
|
|
|
5
5
|
readonly modifier?: number;
|
|
6
6
|
readonly chance: number;
|
|
7
7
|
readonly roles: Role[];
|
|
8
|
+
readonly maxRarity?: Rarity;
|
|
8
9
|
}
|
|
9
10
|
export declare enum TraitEnum {
|
|
10
11
|
/**
|
|
@@ -45,9 +46,47 @@ export declare enum TraitEnum {
|
|
|
45
46
|
/**
|
|
46
47
|
* Gives the player a chance to perform a perfect reception.
|
|
47
48
|
*/
|
|
48
|
-
DEFENSIVE_SPECIALIST = "DEFENSIVE_SPECIALIST"
|
|
49
|
+
DEFENSIVE_SPECIALIST = "DEFENSIVE_SPECIALIST",
|
|
50
|
+
/**
|
|
51
|
+
* Three good receptions/digs/sets in a row make the next reception/dig/set a guaranteed critical that
|
|
52
|
+
* cannot fail.
|
|
53
|
+
*/
|
|
54
|
+
QUICK_LEARNER = "QUICK_LEARNER",
|
|
55
|
+
/**
|
|
56
|
+
* Each successful attack ramps up the spike, and a kill ramps it more. Starts with a small penalty and
|
|
57
|
+
* resets on an attacking error.
|
|
58
|
+
*/
|
|
59
|
+
MOMENTUM_ADDICT = "MOMENTUM_ADDICT",
|
|
60
|
+
/**
|
|
61
|
+
* A front-row kill demoralizes the opponents who faced it, debuffing them for a few rallies.
|
|
62
|
+
*/
|
|
63
|
+
LOUDMOUTH = "LOUDMOUTH",
|
|
64
|
+
/**
|
|
65
|
+
* When a teammate makes a non-block mistake, that teammate's next action cannot fail.
|
|
66
|
+
*/
|
|
67
|
+
TRUE_LEADER = "TRUE_LEADER",
|
|
68
|
+
/**
|
|
69
|
+
* Reacting to a strong opponent action (block/receive), this player can rise to match it. Limited to
|
|
70
|
+
* Mythic rarity and below.
|
|
71
|
+
*/
|
|
72
|
+
OVERACHIEVER = "OVERACHIEVER",
|
|
73
|
+
/**
|
|
74
|
+
* Opponents who interact with this player's serve or attack spend twice the energy (VIGOROUS is nullified).
|
|
75
|
+
*/
|
|
76
|
+
CRAFTY = "CRAFTY",
|
|
77
|
+
/**
|
|
78
|
+
* When the team loses several points in a row, the whole on-court team gets a buff that grows with the
|
|
79
|
+
* streak and disappears the moment they win a point.
|
|
80
|
+
*/
|
|
81
|
+
TENACIOUS = "TENACIOUS",
|
|
82
|
+
/**
|
|
83
|
+
* Serve trait, rolled before the ambient setter/opposite hunt: a chance to serve a precise target (the
|
|
84
|
+
* setter, opposite, or best back-row attacker, depending on serve type and rotation), bypassing GUARDIAN,
|
|
85
|
+
* with a slight serve bonus and reducing the hunted player's attack involvement that rally.
|
|
86
|
+
*/
|
|
87
|
+
HUNTER = "HUNTER"
|
|
49
88
|
}
|
|
50
|
-
export type Trait = TraitEnum.FLOAT_SERVE | TraitEnum.SURPRISE_ATTACK | TraitEnum.GUARDIAN | TraitEnum.MASTER_MIND | TraitEnum.MOVING_WALL | TraitEnum.MARKSMAN | TraitEnum.METEOR_SERVE | TraitEnum.VIGOROUS | TraitEnum.DEFENSIVE_SPECIALIST;
|
|
89
|
+
export type Trait = TraitEnum.FLOAT_SERVE | TraitEnum.SURPRISE_ATTACK | TraitEnum.GUARDIAN | TraitEnum.MASTER_MIND | TraitEnum.MOVING_WALL | TraitEnum.MARKSMAN | TraitEnum.METEOR_SERVE | TraitEnum.VIGOROUS | TraitEnum.DEFENSIVE_SPECIALIST | TraitEnum.QUICK_LEARNER | TraitEnum.MOMENTUM_ADDICT | TraitEnum.LOUDMOUTH | TraitEnum.TRUE_LEADER | TraitEnum.OVERACHIEVER | TraitEnum.CRAFTY | TraitEnum.TENACIOUS | TraitEnum.HUNTER;
|
|
51
90
|
export declare function assignTraits(roles: Role[], rarity: Rarity, maxTraits?: boolean): Trait[];
|
|
52
91
|
export declare const traitMap: Map<Trait, TraitProps>;
|
|
53
92
|
export {};
|
|
@@ -3,6 +3,14 @@ import { randomInt } from 'node:crypto';
|
|
|
3
3
|
import rawTraits from '../../stat-config/traits.json';
|
|
4
4
|
import { shuffle } from '../utils';
|
|
5
5
|
const traits = rawTraits;
|
|
6
|
+
// Ascending rarity order, used by the maxRarity trait-eligibility gate in assignTraits.
|
|
7
|
+
const RARITY_RANK = {
|
|
8
|
+
[RarityEnum.COMMON]: 0,
|
|
9
|
+
[RarityEnum.RARE]: 1,
|
|
10
|
+
[RarityEnum.LEGENDARY]: 2,
|
|
11
|
+
[RarityEnum.MYTHIC]: 3,
|
|
12
|
+
[RarityEnum.SPECIAL]: 4
|
|
13
|
+
};
|
|
6
14
|
export var TraitEnum;
|
|
7
15
|
(function (TraitEnum) {
|
|
8
16
|
/**
|
|
@@ -44,6 +52,44 @@ export var TraitEnum;
|
|
|
44
52
|
* Gives the player a chance to perform a perfect reception.
|
|
45
53
|
*/
|
|
46
54
|
TraitEnum["DEFENSIVE_SPECIALIST"] = "DEFENSIVE_SPECIALIST";
|
|
55
|
+
/**
|
|
56
|
+
* Three good receptions/digs/sets in a row make the next reception/dig/set a guaranteed critical that
|
|
57
|
+
* cannot fail.
|
|
58
|
+
*/
|
|
59
|
+
TraitEnum["QUICK_LEARNER"] = "QUICK_LEARNER";
|
|
60
|
+
/**
|
|
61
|
+
* Each successful attack ramps up the spike, and a kill ramps it more. Starts with a small penalty and
|
|
62
|
+
* resets on an attacking error.
|
|
63
|
+
*/
|
|
64
|
+
TraitEnum["MOMENTUM_ADDICT"] = "MOMENTUM_ADDICT";
|
|
65
|
+
/**
|
|
66
|
+
* A front-row kill demoralizes the opponents who faced it, debuffing them for a few rallies.
|
|
67
|
+
*/
|
|
68
|
+
TraitEnum["LOUDMOUTH"] = "LOUDMOUTH";
|
|
69
|
+
/**
|
|
70
|
+
* When a teammate makes a non-block mistake, that teammate's next action cannot fail.
|
|
71
|
+
*/
|
|
72
|
+
TraitEnum["TRUE_LEADER"] = "TRUE_LEADER";
|
|
73
|
+
/**
|
|
74
|
+
* Reacting to a strong opponent action (block/receive), this player can rise to match it. Limited to
|
|
75
|
+
* Mythic rarity and below.
|
|
76
|
+
*/
|
|
77
|
+
TraitEnum["OVERACHIEVER"] = "OVERACHIEVER";
|
|
78
|
+
/**
|
|
79
|
+
* Opponents who interact with this player's serve or attack spend twice the energy (VIGOROUS is nullified).
|
|
80
|
+
*/
|
|
81
|
+
TraitEnum["CRAFTY"] = "CRAFTY";
|
|
82
|
+
/**
|
|
83
|
+
* When the team loses several points in a row, the whole on-court team gets a buff that grows with the
|
|
84
|
+
* streak and disappears the moment they win a point.
|
|
85
|
+
*/
|
|
86
|
+
TraitEnum["TENACIOUS"] = "TENACIOUS";
|
|
87
|
+
/**
|
|
88
|
+
* Serve trait, rolled before the ambient setter/opposite hunt: a chance to serve a precise target (the
|
|
89
|
+
* setter, opposite, or best back-row attacker, depending on serve type and rotation), bypassing GUARDIAN,
|
|
90
|
+
* with a slight serve bonus and reducing the hunted player's attack involvement that rally.
|
|
91
|
+
*/
|
|
92
|
+
TraitEnum["HUNTER"] = "HUNTER";
|
|
47
93
|
})(TraitEnum || (TraitEnum = {}));
|
|
48
94
|
export function assignTraits(roles, rarity, maxTraits) {
|
|
49
95
|
let traitCount;
|
|
@@ -75,7 +121,9 @@ export function assignTraits(roles, rarity, maxTraits) {
|
|
|
75
121
|
return [];
|
|
76
122
|
const filteredTraits = traits.filter((trait) => {
|
|
77
123
|
const setA = new Set(trait.roles);
|
|
78
|
-
|
|
124
|
+
const roleMatch = roles.some(el => setA.has(el));
|
|
125
|
+
const rarityOk = trait.maxRarity == null || RARITY_RANK[rarity] <= RARITY_RANK[trait.maxRarity];
|
|
126
|
+
return roleMatch && rarityOk;
|
|
79
127
|
}).map(trait => trait.name);
|
|
80
128
|
return shuffle(filteredTraits).slice(0, traitCount);
|
|
81
129
|
}
|
|
@@ -90,5 +90,79 @@
|
|
|
90
90
|
"OUTSIDE_HITTER",
|
|
91
91
|
"MIDDLE_BLOCKER"
|
|
92
92
|
]
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"name": "QUICK_LEARNER",
|
|
96
|
+
"chance": 1,
|
|
97
|
+
"roles": [
|
|
98
|
+
"SETTER",
|
|
99
|
+
"LIBERO",
|
|
100
|
+
"OUTSIDE_HITTER"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"name": "MOMENTUM_ADDICT",
|
|
105
|
+
"chance": 1,
|
|
106
|
+
"roles": [
|
|
107
|
+
"OUTSIDE_HITTER",
|
|
108
|
+
"OPPOSITE_HITTER",
|
|
109
|
+
"MIDDLE_BLOCKER"
|
|
110
|
+
]
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"name": "LOUDMOUTH",
|
|
114
|
+
"chance": 0.25,
|
|
115
|
+
"roles": [
|
|
116
|
+
"OUTSIDE_HITTER",
|
|
117
|
+
"OPPOSITE_HITTER",
|
|
118
|
+
"MIDDLE_BLOCKER"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"name": "TRUE_LEADER",
|
|
123
|
+
"chance": 0.3,
|
|
124
|
+
"roles": [
|
|
125
|
+
"SETTER",
|
|
126
|
+
"LIBERO",
|
|
127
|
+
"OUTSIDE_HITTER"
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"name": "OVERACHIEVER",
|
|
132
|
+
"chance": 0.2,
|
|
133
|
+
"maxRarity": "MYTHIC",
|
|
134
|
+
"roles": [
|
|
135
|
+
"LIBERO",
|
|
136
|
+
"OUTSIDE_HITTER",
|
|
137
|
+
"MIDDLE_BLOCKER"
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"name": "CRAFTY",
|
|
142
|
+
"chance": 0.3,
|
|
143
|
+
"roles": [
|
|
144
|
+
"SETTER",
|
|
145
|
+
"OUTSIDE_HITTER",
|
|
146
|
+
"OPPOSITE_HITTER",
|
|
147
|
+
"MIDDLE_BLOCKER"
|
|
148
|
+
]
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
"name": "TENACIOUS",
|
|
152
|
+
"chance": 1,
|
|
153
|
+
"roles": [
|
|
154
|
+
"SETTER",
|
|
155
|
+
"LIBERO",
|
|
156
|
+
"OUTSIDE_HITTER"
|
|
157
|
+
]
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"name": "HUNTER",
|
|
161
|
+
"chance": 0.15,
|
|
162
|
+
"roles": [
|
|
163
|
+
"SETTER",
|
|
164
|
+
"OPPOSITE_HITTER",
|
|
165
|
+
"OUTSIDE_HITTER"
|
|
166
|
+
]
|
|
93
167
|
}
|
|
94
168
|
]
|