enefel 2.9.1 → 2.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +7 -0
- package/2025/newSkills.ts +769 -0
- package/2025/raceMigration.ts +66 -0
- package/2025/rawTeamsData.ts +1726 -0
- package/2025/skillMigration.ts +155 -0
- package/avatarsSeason.ts +61 -0
- package/career.ts +64 -8
- package/career2025.ts +2752 -0
- package/dice.ts +40 -8
- package/dist/2025/newSkills.d.ts +10 -0
- package/dist/2025/newSkills.js +663 -0
- package/dist/2025/raceMigration.d.ts +10 -0
- package/dist/2025/raceMigration.js +53 -0
- package/dist/2025/rawTeamsData.d.ts +12 -0
- package/dist/2025/rawTeamsData.js +1699 -0
- package/dist/2025/skillMigration.d.ts +31 -0
- package/dist/2025/skillMigration.js +95 -0
- package/dist/avatarsSeason.d.ts +22 -0
- package/dist/avatarsSeason.js +54 -0
- package/dist/career.d.ts +13 -4
- package/dist/career.js +36 -7
- package/dist/career2025.d.ts +192 -0
- package/dist/career2025.js +2611 -0
- package/dist/dice.d.ts +10 -2
- package/dist/dice.js +31 -8
- package/dist/index.d.ts +17 -2
- package/dist/index.js +44 -5
- package/dist/move.d.ts +6 -2
- package/dist/move.js +35 -0
- package/dist/package-lock.json +913 -7
- package/dist/package.json +6 -2
- package/dist/pitch.d.ts +10 -1
- package/dist/pitch.js +16 -0
- package/dist/player.d.ts +8 -4
- package/dist/player.js +104 -20
- package/dist/position.d.ts +4 -0
- package/dist/position.js +17 -1
- package/dist/race.d.ts +23 -12
- package/dist/race.js +210 -2
- package/dist/skill.d.ts +26 -3
- package/dist/skill.js +199 -81
- package/dist/skills/hitAndRun.d.ts +10 -0
- package/dist/skills/hitAndRun.js +12 -0
- package/dist/skills/safePairOfHands.d.ts +28 -0
- package/dist/skills/safePairOfHands.js +18 -0
- package/dist/skills/sidestep.d.ts +21 -0
- package/dist/skills/sidestep.js +20 -0
- package/dist/status.d.ts +4 -1
- package/dist/status.js +14 -4
- package/dist/store.d.ts +3 -0
- package/dist/store.js +3 -0
- package/dist/teams/career_v2025.d.ts +246 -0
- package/dist/teams/career_v2025.js +3512 -0
- package/dist/teams/convert-csv-to-career.d.ts +1 -0
- package/dist/teams/convert-csv-to-career.js +1085 -0
- package/dist/types/models.d.ts +4 -0
- package/index.ts +57 -4
- package/jest.config.js +3 -0
- package/move.ts +50 -2
- package/npm-login.sh +0 -0
- package/package.json +6 -2
- package/pitch.ts +22 -0
- package/player.ts +105 -22
- package/position.ts +16 -0
- package/race.ts +227 -13
- package/skill.ts +217 -83
- package/skills/hitAndRun.ts +14 -0
- package/skills/safePairOfHands.ts +33 -0
- package/skills/sidestep.ts +25 -0
- package/status.ts +15 -3
- package/store.ts +3 -0
- package/teams/README.md +53 -0
- package/teams/clean-stats.js +54 -0
- package/teams/convert-csv-to-career.ts +1209 -0
- package/teams/players_clean.csv +107 -0
- package/teams/players_next.csv +21 -0
- package/types/models.ts +4 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { SKILL_TYPE } from "../skill";
|
|
2
|
+
|
|
3
|
+
type CareerLite = {
|
|
4
|
+
skills?: (string | [string, number])[];
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
type SkillBasic = {
|
|
8
|
+
id: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
family?: string;
|
|
11
|
+
mode?: string;
|
|
12
|
+
elite?: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type SkillMigrationRow = {
|
|
16
|
+
key: string;
|
|
17
|
+
label: string;
|
|
18
|
+
intrinsic: boolean;
|
|
19
|
+
legacy?: {
|
|
20
|
+
name: string;
|
|
21
|
+
family: string;
|
|
22
|
+
};
|
|
23
|
+
next?: {
|
|
24
|
+
name: string;
|
|
25
|
+
family?: string;
|
|
26
|
+
mode?: string;
|
|
27
|
+
elite?: boolean;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const SKILL_DISPLAY_OVERRIDE: Record<string, string> = {
|
|
32
|
+
"animal-salvagery": "Animal Savagery",
|
|
33
|
+
"distrubing-presence": "Disturbing Presence",
|
|
34
|
+
claw: "Claws",
|
|
35
|
+
animosity: "Animosity (X)",
|
|
36
|
+
"running-pass": "Give and Go", // GIVE_AND_GO renamed to Give and Go
|
|
37
|
+
runningpass: "Give and Go", // Alias for GIVE_AND_GO
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const SKILL_KEY_ALIAS: Record<string, string> = {
|
|
41
|
+
fumblerooskie: "fumblerooski",
|
|
42
|
+
giveandgo: "runningpass",
|
|
43
|
+
animalsalvagery: "animalsavagery",
|
|
44
|
+
distrubingpresence: "disturbingpresence",
|
|
45
|
+
claws: "claw",
|
|
46
|
+
animosityx: "animosity",
|
|
47
|
+
nohand: "noball",
|
|
48
|
+
lonerx: "loner",
|
|
49
|
+
pogostick: "pogo",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const normalizeSkillKey = (value: string) => {
|
|
53
|
+
const base = value.toLowerCase().replace(/[^a-z0-9]/gi, "");
|
|
54
|
+
return SKILL_KEY_ALIAS[base] ?? base;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const formatSkillName = (value: string) =>
|
|
58
|
+
value.replace(/-/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
59
|
+
|
|
60
|
+
const buildSkillMigrationRows = (
|
|
61
|
+
existingSkills: Record<string, SKILL_TYPE>,
|
|
62
|
+
nextSkills: SkillBasic[],
|
|
63
|
+
legacyCareers: Record<string, CareerLite>,
|
|
64
|
+
nextCareers: Record<string, CareerLite>
|
|
65
|
+
): SkillMigrationRow[] => {
|
|
66
|
+
const labelByType: Record<SKILL_TYPE, string> = {
|
|
67
|
+
[SKILL_TYPE.AGILITY]: "Agility",
|
|
68
|
+
[SKILL_TYPE.EXTRAORDINARY]: "Extraordinary",
|
|
69
|
+
[SKILL_TYPE.GENERAL]: "General",
|
|
70
|
+
[SKILL_TYPE.MUTATION]: "Mutation",
|
|
71
|
+
[SKILL_TYPE.PASSING]: "Passing",
|
|
72
|
+
[SKILL_TYPE.STRENGTH]: "Strength",
|
|
73
|
+
[SKILL_TYPE.DEVIOUS]: "Devious",
|
|
74
|
+
[SKILL_TYPE.SPECIAL]: "Special",
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const intrinsicSkills = new Set<string>();
|
|
78
|
+
const collectSkills = (careers: Record<string, CareerLite>) => {
|
|
79
|
+
Object.values(careers).forEach((career) => {
|
|
80
|
+
(career.skills ?? []).forEach((s) => {
|
|
81
|
+
const skillName = Array.isArray(s) ? s[0] : s;
|
|
82
|
+
intrinsicSkills.add(normalizeSkillKey(String(skillName)));
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
};
|
|
86
|
+
collectSkills(legacyCareers);
|
|
87
|
+
collectSkills(nextCareers);
|
|
88
|
+
|
|
89
|
+
const existingMap = new Map<
|
|
90
|
+
string,
|
|
91
|
+
{
|
|
92
|
+
name: string;
|
|
93
|
+
family: string;
|
|
94
|
+
}
|
|
95
|
+
>();
|
|
96
|
+
Object.entries(existingSkills).forEach(([id, type]) => {
|
|
97
|
+
const key = normalizeSkillKey(id);
|
|
98
|
+
const display = SKILL_DISPLAY_OVERRIDE[id] ?? formatSkillName(id);
|
|
99
|
+
existingMap.set(key, {
|
|
100
|
+
name: display,
|
|
101
|
+
family: labelByType[type] ?? String(type),
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
const nextMap = new Map<
|
|
106
|
+
string,
|
|
107
|
+
{
|
|
108
|
+
name: string;
|
|
109
|
+
family?: string;
|
|
110
|
+
mode?: string;
|
|
111
|
+
elite?: boolean;
|
|
112
|
+
}
|
|
113
|
+
>();
|
|
114
|
+
nextSkills.forEach((skill) => {
|
|
115
|
+
const key = normalizeSkillKey(skill.id);
|
|
116
|
+
nextMap.set(key, {
|
|
117
|
+
name: skill.name ?? formatSkillName(skill.id),
|
|
118
|
+
family: skill.family,
|
|
119
|
+
mode: skill.mode,
|
|
120
|
+
elite: skill.elite,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const keys: string[] = [];
|
|
125
|
+
existingMap.forEach((_v, key) => keys.push(key));
|
|
126
|
+
nextMap.forEach((_v, key) => {
|
|
127
|
+
if (!existingMap.has(key)) {
|
|
128
|
+
keys.push(key);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
return keys
|
|
133
|
+
.map((key) => {
|
|
134
|
+
const legacy = existingMap.get(key);
|
|
135
|
+
const next = nextMap.get(key);
|
|
136
|
+
const label = next?.name ?? legacy?.name ?? key;
|
|
137
|
+
return {
|
|
138
|
+
key,
|
|
139
|
+
label,
|
|
140
|
+
legacy,
|
|
141
|
+
next,
|
|
142
|
+
intrinsic: intrinsicSkills.has(key),
|
|
143
|
+
};
|
|
144
|
+
})
|
|
145
|
+
.sort((a, b) => a.label.localeCompare(b.label));
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
export {
|
|
149
|
+
buildSkillMigrationRows,
|
|
150
|
+
formatSkillName,
|
|
151
|
+
normalizeSkillKey,
|
|
152
|
+
SKILL_DISPLAY_OVERRIDE,
|
|
153
|
+
SkillBasic,
|
|
154
|
+
SkillMigrationRow,
|
|
155
|
+
};
|
package/avatarsSeason.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AVATAR_RARITY } from "./career";
|
|
2
|
+
|
|
3
|
+
export type SeasonAvatar = {
|
|
4
|
+
file: string;
|
|
5
|
+
season: number;
|
|
6
|
+
rarity: AVATAR_RARITY;
|
|
7
|
+
/** true for portrait images (ratio 2:3, e.g. 1024×1536) */
|
|
8
|
+
portrait?: boolean;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
/** Display height multiplier for portrait avatars (2:3 ratio) */
|
|
12
|
+
export const PORTRAIT_RATIO = 1.5;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Avatars saisonniers — universels (aucune restriction de race).
|
|
16
|
+
* Pour ajouter des avatars : déposer l'image dans
|
|
17
|
+
* client/public/tile/shop/avatar-season/s{season}/
|
|
18
|
+
* et ajouter une entrée ici.
|
|
19
|
+
*/
|
|
20
|
+
export const AVATAR_SEASON_LIST: SeasonAvatar[] = [
|
|
21
|
+
{ file: "1.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
22
|
+
{ file: "2.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
23
|
+
{ file: "3.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
24
|
+
{ file: "4.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
25
|
+
{ file: "5.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
26
|
+
{ file: "6.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
27
|
+
{ file: "7.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
28
|
+
{ file: "8.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
29
|
+
{ file: "9.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
30
|
+
{ file: "10.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
31
|
+
{ file: "11.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
32
|
+
{ file: "12.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
33
|
+
{ file: "13.png", season: 17, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
34
|
+
{ file: "1.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
35
|
+
{ file: "2.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
36
|
+
{ file: "3.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
37
|
+
{ file: "4.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
38
|
+
{ file: "5.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
39
|
+
{ file: "6.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
40
|
+
{ file: "7.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
41
|
+
{ file: "8.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
42
|
+
{ file: "9.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
43
|
+
{ file: "10.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
44
|
+
{ file: "11.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
45
|
+
{ file: "12.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
46
|
+
{ file: "13.png", season: 19, rarity: AVATAR_RARITY.SEASONAL, portrait: true },
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
/** Chemin complet utilisé pour afficher l'avatar d'un joueur (ex: <img src>) */
|
|
50
|
+
export function getSeasonAvatarPath(season: number): string {
|
|
51
|
+
return `tile/shop/avatar-season/s${season}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Chemin relatif utilisé comme prop `type` dans le composant Item du shop */
|
|
55
|
+
export function getSeasonAvatarItemType(season: number): string {
|
|
56
|
+
return `avatar-season/s${season}`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function findSeasonAvatar(file: string): SeasonAvatar | undefined {
|
|
60
|
+
return AVATAR_SEASON_LIST.find((a) => a.file === file);
|
|
61
|
+
}
|
package/career.ts
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
// AG: Agility
|
|
4
4
|
// AV: Armour Value
|
|
5
5
|
|
|
6
|
+
import {
|
|
7
|
+
CAREER_ID as CAREER_ID_2025,
|
|
8
|
+
Career as Career2025,
|
|
9
|
+
getCareers as getCareers2025,
|
|
10
|
+
} from "./career2025";
|
|
6
11
|
import { SKILL_NAMES } from "./skill";
|
|
7
12
|
|
|
8
13
|
enum RACE {
|
|
@@ -34,6 +39,7 @@ enum AVATAR_RARITY {
|
|
|
34
39
|
COMMUN = "c",
|
|
35
40
|
RARE = "r",
|
|
36
41
|
UNIQUE = "u",
|
|
42
|
+
SEASONAL = "s",
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
enum AVATAR {
|
|
@@ -178,6 +184,7 @@ enum CAREER_ID {
|
|
|
178
184
|
enum CAREER_VERSION {
|
|
179
185
|
V6 = "v6",
|
|
180
186
|
V2020 = "v2020",
|
|
187
|
+
V2025 = "v2025",
|
|
181
188
|
}
|
|
182
189
|
|
|
183
190
|
export type Career = {
|
|
@@ -199,6 +206,10 @@ export type Career = {
|
|
|
199
206
|
version: CAREER_VERSION;
|
|
200
207
|
};
|
|
201
208
|
|
|
209
|
+
type CAREER_ID_ALL = CAREER_ID | CAREER_ID_2025;
|
|
210
|
+
type CareerMap = Record<CAREER_ID_ALL, Career | Career2025>;
|
|
211
|
+
type AvailableCareerMap = Record<CAREER_ID_2025, Career2025>;
|
|
212
|
+
|
|
202
213
|
const CAREER: Record<CAREER_ID, Career> = {
|
|
203
214
|
// SLANN
|
|
204
215
|
[CAREER_ID.SLANN_LINEMAN]: {
|
|
@@ -690,11 +701,7 @@ const CAREER: Record<CAREER_ID, Career> = {
|
|
|
690
701
|
double: "AS",
|
|
691
702
|
normalCoach: "G",
|
|
692
703
|
icons: ["imperial-thrower1"],
|
|
693
|
-
skills: [
|
|
694
|
-
SKILL_NAMES.PASS,
|
|
695
|
-
SKILL_NAMES.RUNNING_PASS,
|
|
696
|
-
SKILL_NAMES.SPECIALIST,
|
|
697
|
-
],
|
|
704
|
+
skills: [SKILL_NAMES.PASS, SKILL_NAMES.GIVE_AND_GO, SKILL_NAMES.SPECIALIST],
|
|
698
705
|
avatars: [AVATAR.HUMAN, AVATAR.HUMAN_WOMAN],
|
|
699
706
|
badge: RACE.IMPERIAL,
|
|
700
707
|
range: 1,
|
|
@@ -2158,8 +2165,57 @@ const CAREER: Record<CAREER_ID, Career> = {
|
|
|
2158
2165
|
},
|
|
2159
2166
|
};
|
|
2160
2167
|
|
|
2161
|
-
const getCareers = ():
|
|
2162
|
-
|
|
2168
|
+
const getCareers = (): CareerMap => {
|
|
2169
|
+
const nextCareers = getCareers2025();
|
|
2170
|
+
return {
|
|
2171
|
+
...(CAREER as CareerMap),
|
|
2172
|
+
...(nextCareers as CareerMap),
|
|
2173
|
+
};
|
|
2174
|
+
};
|
|
2175
|
+
|
|
2176
|
+
const getAvailableCareers = (): AvailableCareerMap => {
|
|
2177
|
+
const nextCareers = getCareers2025();
|
|
2178
|
+
const allowedBadges = new Set<string>(Object.values(RACE));
|
|
2179
|
+
|
|
2180
|
+
return Object.entries(nextCareers).reduce<AvailableCareerMap>(
|
|
2181
|
+
(acc, [id, career]) => {
|
|
2182
|
+
if (allowedBadges.has(career.badge as unknown as string)) {
|
|
2183
|
+
acc[id as CAREER_ID_2025] = career as Career2025;
|
|
2184
|
+
}
|
|
2185
|
+
return acc;
|
|
2186
|
+
},
|
|
2187
|
+
{} as AvailableCareerMap
|
|
2188
|
+
);
|
|
2163
2189
|
};
|
|
2164
2190
|
|
|
2165
|
-
|
|
2191
|
+
const CAREER_IS_2025: Record<CAREER_ID, boolean> = Object.values(
|
|
2192
|
+
CAREER_ID
|
|
2193
|
+
).reduce((acc, id) => {
|
|
2194
|
+
acc[id as CAREER_ID] = new Set<string>(
|
|
2195
|
+
Object.values(CAREER_ID_2025) as string[]
|
|
2196
|
+
).has(id as unknown as string);
|
|
2197
|
+
return acc;
|
|
2198
|
+
}, {} as Record<CAREER_ID, boolean>);
|
|
2199
|
+
|
|
2200
|
+
// Migration 2025 : indique si un career legacy existe en v2025
|
|
2201
|
+
const CAREER_MIGRATION_2025: Record<CAREER_ID, boolean> = (() => {
|
|
2202
|
+
const migrated = new Set<string>(Object.values(CAREER_ID_2025));
|
|
2203
|
+
const map = {} as Record<CAREER_ID, boolean>;
|
|
2204
|
+
(Object.values(CAREER_ID) as CAREER_ID[]).forEach((id) => {
|
|
2205
|
+
map[id] = migrated.has(id as string);
|
|
2206
|
+
});
|
|
2207
|
+
return map;
|
|
2208
|
+
})();
|
|
2209
|
+
|
|
2210
|
+
export {
|
|
2211
|
+
AVATAR,
|
|
2212
|
+
AVATAR_RARITY,
|
|
2213
|
+
CAREER_ID,
|
|
2214
|
+
CAREER_ID_ALL,
|
|
2215
|
+
CAREER_IS_2025,
|
|
2216
|
+
CAREER_MIGRATION_2025,
|
|
2217
|
+
CAREER_VERSION,
|
|
2218
|
+
RACE,
|
|
2219
|
+
getAvailableCareers,
|
|
2220
|
+
getCareers,
|
|
2221
|
+
};
|