enefel 1.0.96 → 1.0.100
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/calcul.js +8 -0
- package/index.js +32 -8
- package/league.js +142 -25
- package/package.json +1 -1
- package/race.js +23 -23
- package/skill.js +35 -0
- package/skillCoach.js +5 -1
package/calcul.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const distance = (p1, p2) => {
|
|
2
|
+
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
const distanceSquares = (p1, p2, distance) => {
|
|
6
|
+
return Math.abs(p1.x - p2.x) <= distance && Math.abs(p1.y - p2.y) <= distance;
|
|
7
|
+
};
|
|
8
|
+
module.exports = { distance, distanceSquares };
|
package/index.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const {
|
|
2
|
+
hasSkill,
|
|
3
|
+
SKILL_NAMES,
|
|
4
|
+
getDisturbingPresenceMalus,
|
|
5
|
+
} = require("./skill");
|
|
2
6
|
const { ranges } = require("./improvement");
|
|
3
7
|
const races = require("./race");
|
|
4
8
|
const {
|
|
@@ -14,6 +18,7 @@ const {
|
|
|
14
18
|
meteoMaxPassDistance,
|
|
15
19
|
METEO,
|
|
16
20
|
} = require("./meteo");
|
|
21
|
+
const { distance } = require("./calcul");
|
|
17
22
|
const INITIAL_REROLL = 2;
|
|
18
23
|
const POSTULATION_HOURS = 24;
|
|
19
24
|
const INACTIVE_DAYS = 10;
|
|
@@ -207,6 +212,7 @@ const GAME_TYPE = {
|
|
|
207
212
|
DIVISION: "division",
|
|
208
213
|
FRIENDLY: "friendly",
|
|
209
214
|
OPEN: "open",
|
|
215
|
+
PLAYOFF: "playoff",
|
|
210
216
|
};
|
|
211
217
|
|
|
212
218
|
const TAKE_BALL_TYPE = {
|
|
@@ -580,10 +586,6 @@ const availableSquaresToPushBack = (p1, p2) => {
|
|
|
580
586
|
}
|
|
581
587
|
};
|
|
582
588
|
|
|
583
|
-
const distance = (p1, p2) => {
|
|
584
|
-
return Math.sqrt(Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2));
|
|
585
|
-
};
|
|
586
|
-
|
|
587
589
|
// playerFrom, pointTo, foe
|
|
588
590
|
const isOnLine = (A, B, C) => {
|
|
589
591
|
//http://www.luccini.it/bloodbowl/downloads/Tabella_Intercetti.pdf
|
|
@@ -673,7 +675,8 @@ const getBestInterceptor = (playerFrom, pointTo, players) => {
|
|
|
673
675
|
let bestAGPlayers = [];
|
|
674
676
|
possiblePlayers.forEach((player) => {
|
|
675
677
|
const zdt = getEnemyTackleZones(player, player.teamId, players).length;
|
|
676
|
-
|
|
678
|
+
const disturbingPresence = getDisturbingPresenceMalus(player, players);
|
|
679
|
+
if (player.current_AG - zdt - disturbingPresence > bestAG) {
|
|
677
680
|
bestAG = player.current_AG - zdt;
|
|
678
681
|
bestAGPlayers = [];
|
|
679
682
|
bestAGPlayers.push(player);
|
|
@@ -875,8 +878,27 @@ const getDefenderStrength = (player) => {
|
|
|
875
878
|
return player.current_ST;
|
|
876
879
|
};
|
|
877
880
|
|
|
881
|
+
const arrayMove = (arr, old_index, new_index) => {
|
|
882
|
+
if (new_index >= arr.length) {
|
|
883
|
+
var k = new_index - arr.length + 1;
|
|
884
|
+
while (k--) {
|
|
885
|
+
arr.push(undefined);
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
arr.splice(new_index, 0, arr.splice(old_index, 1)[0]);
|
|
889
|
+
return arr; // for testing
|
|
890
|
+
};
|
|
891
|
+
|
|
892
|
+
const swapArrayLocs = (arr, index1, index2) => {
|
|
893
|
+
var temp = arr[index1];
|
|
894
|
+
|
|
895
|
+
arr[index1] = arr[index2];
|
|
896
|
+
arr[index2] = temp;
|
|
897
|
+
|
|
898
|
+
return arr;
|
|
899
|
+
};
|
|
900
|
+
|
|
878
901
|
module.exports = {
|
|
879
|
-
getDefenderStrength,
|
|
880
902
|
addSeconds,
|
|
881
903
|
availableSquaresToPushBack,
|
|
882
904
|
canBlock,
|
|
@@ -889,7 +911,6 @@ module.exports = {
|
|
|
889
911
|
canStandup,
|
|
890
912
|
canThrowTeamMate,
|
|
891
913
|
canTransmit,
|
|
892
|
-
distance,
|
|
893
914
|
FORMATION_DEFAULT_NAME,
|
|
894
915
|
GAME_HISTORY_INFO,
|
|
895
916
|
GAME_HISTORY_TYPE,
|
|
@@ -899,6 +920,7 @@ module.exports = {
|
|
|
899
920
|
getBestInterceptor,
|
|
900
921
|
getBlockAssistance,
|
|
901
922
|
getCareers,
|
|
923
|
+
getDefenderStrength,
|
|
902
924
|
getDicesBlock,
|
|
903
925
|
getEnemyTackleZones,
|
|
904
926
|
getMaxGfi,
|
|
@@ -920,11 +942,13 @@ module.exports = {
|
|
|
920
942
|
LAST_SEASON_ALPHA,
|
|
921
943
|
MAX_PLAYER_TEAM,
|
|
922
944
|
MAX_PLAYER_USER,
|
|
945
|
+
swapArrayLocs,
|
|
923
946
|
p,
|
|
924
947
|
PLAYER_HISTORY_INFO,
|
|
925
948
|
PLAYER_HISTORY_TYPE,
|
|
926
949
|
PLAYER_STAT,
|
|
927
950
|
POSTULATION_HOURS,
|
|
928
951
|
shuffleArray,
|
|
952
|
+
arrayMove,
|
|
929
953
|
TAKE_BALL_TYPE,
|
|
930
954
|
};
|
package/league.js
CHANGED
|
@@ -1,15 +1,72 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { GAME_TYPE } = require(".");
|
|
2
|
+
const { canPlayLeague } = require("./state");
|
|
2
3
|
|
|
3
4
|
const GROUP_SIZE = 4;
|
|
5
|
+
const HAS_NEXT_SEASON_PLAYOFF = true;
|
|
6
|
+
|
|
7
|
+
const calculateTeamsStandingForPlayoff = (flatTeams, division) => {
|
|
8
|
+
const standings = [{ teams: [] }];
|
|
9
|
+
|
|
10
|
+
for (let team of flatTeams) {
|
|
11
|
+
standings[standings.length - 1].teams.push(team);
|
|
12
|
+
if (
|
|
13
|
+
standings[standings.length - 1].teams.length >= GROUP_SIZE &&
|
|
14
|
+
standings.length < 3
|
|
15
|
+
) {
|
|
16
|
+
standings.push({ teams: [] });
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (division.length <= 2) {
|
|
21
|
+
// On prends les 8 premiers
|
|
22
|
+
} else {
|
|
23
|
+
for (let i = 0; i < standings.length - 1; ++i) {
|
|
24
|
+
const currentDivision = standings[i];
|
|
25
|
+
const isLeagueA = i === 0;
|
|
26
|
+
const isLeagueB = i === 1;
|
|
27
|
+
// Les derniers des ligues A et B sont relegué dans la league open
|
|
28
|
+
const nextDivisionIndex = i + (isLeagueA ? 2 : 1);
|
|
29
|
+
// TODO : Ce truc doit ps etre fait si la saison courante et pas un playoff
|
|
30
|
+
const nextDivision = standings[nextDivisionIndex];
|
|
31
|
+
const currentDivisionLastTeam =
|
|
32
|
+
currentDivision.teams[currentDivision.teams.length - 1];
|
|
33
|
+
|
|
34
|
+
// Le dernier de la ligue A va remplacer premier de l'open
|
|
35
|
+
// Le dernier de la ligue B va remplacer le second de l'open
|
|
36
|
+
const nextDivisionFirstTeam = nextDivision.teams[isLeagueB ? 1 : 0];
|
|
37
|
+
|
|
38
|
+
currentDivision.teams[currentDivision.teams.length - 1] =
|
|
39
|
+
nextDivisionFirstTeam;
|
|
40
|
+
|
|
41
|
+
nextDivision.teams[isLeagueB ? 1 : 0] = currentDivisionLastTeam;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
4
44
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
45
|
+
// Les ligues A est B sont classé par ELO
|
|
46
|
+
const flatedTeams = standings.reduce((p, c) => [...p, ...c.teams], []);
|
|
47
|
+
if (!flatedTeams || flatedTeams.length === 0) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const size = GROUP_SIZE * 2;
|
|
51
|
+
for (i = 0; i < size; i++) {
|
|
52
|
+
for (j = i + 1; j < size; j++) {
|
|
53
|
+
if (flatedTeams[j].elo > flatedTeams[i].elo) {
|
|
54
|
+
let temp = flatedTeams[i];
|
|
55
|
+
flatedTeams[i] = flatedTeams[j];
|
|
56
|
+
flatedTeams[j] = temp;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// On met ensemble le 1, 3, 5, 7 et 2, 4, 6, 8 (B)
|
|
61
|
+
for (i = 1; i < GROUP_SIZE; i += 2) {
|
|
62
|
+
let temp = flatedTeams[i];
|
|
63
|
+
flatedTeams[i] = flatedTeams[i + GROUP_SIZE - 1];
|
|
64
|
+
flatedTeams[i + GROUP_SIZE - 1] = temp;
|
|
65
|
+
}
|
|
66
|
+
return flatedTeams;
|
|
8
67
|
};
|
|
9
68
|
|
|
10
|
-
const
|
|
11
|
-
// Standing division should be sorted (1, 2, 3, ... , open)
|
|
12
|
-
const newStandings = JSON.parse(JSON.stringify(division));
|
|
69
|
+
const calculateTeamsStandingForLeagues = (newStandings, division) => {
|
|
13
70
|
for (let i = 0; i < division.length - 1; ++i) {
|
|
14
71
|
const currentDivision = newStandings[i];
|
|
15
72
|
const nextDivision = newStandings[i + 1];
|
|
@@ -18,10 +75,8 @@ const calculateTeamsStandingForNextSeason = (division) => {
|
|
|
18
75
|
currentDivision.teams[currentDivision.teams.length - 1];
|
|
19
76
|
|
|
20
77
|
let indexNextDivisionFirstTeam = 0;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}
|
|
24
|
-
if (nextDivision.name === LEAGUE_NAME.OPEN) {
|
|
78
|
+
|
|
79
|
+
if (nextDivision.name === GAME_TYPE.OPEN) {
|
|
25
80
|
// To avoid some teams block the open, we take the first team with canChampionship
|
|
26
81
|
indexNextDivisionFirstTeam = nextDivision.teams.findIndex(
|
|
27
82
|
(t) => t.canChampionship
|
|
@@ -33,38 +88,89 @@ const calculateTeamsStandingForNextSeason = (division) => {
|
|
|
33
88
|
const nextDivisionFirstTeam =
|
|
34
89
|
nextDivision.teams[indexNextDivisionFirstTeam];
|
|
35
90
|
|
|
36
|
-
currentDivision.teams[
|
|
37
|
-
|
|
38
|
-
] = nextDivisionFirstTeam;
|
|
91
|
+
currentDivision.teams[currentDivision.teams.length - 1] =
|
|
92
|
+
nextDivisionFirstTeam;
|
|
39
93
|
|
|
40
94
|
nextDivision.teams[indexNextDivisionFirstTeam] = currentDivisionLastTeam;
|
|
41
95
|
}
|
|
42
96
|
const flatTeams = newStandings
|
|
43
97
|
.reduce((p, c) => [...p, ...c.teams], [])
|
|
44
|
-
.filter((t) => t &&
|
|
98
|
+
.filter((t) => t && canPlayLeague(t));
|
|
45
99
|
|
|
46
100
|
return flatTeams;
|
|
47
101
|
};
|
|
48
102
|
|
|
103
|
+
const calculateTeamsStandingForNextSeason = (division) => {
|
|
104
|
+
division = division.filter(
|
|
105
|
+
(d) => d.name !== GAME_TYPE.FRIENDLY && d.name !== GAME_TYPE.PLAYOFF
|
|
106
|
+
);
|
|
107
|
+
// Standing division should be sorted (playoff, 1, 2, 3, ... , open)
|
|
108
|
+
const newStandings = JSON.parse(JSON.stringify(division));
|
|
109
|
+
|
|
110
|
+
const flatTeams = newStandings
|
|
111
|
+
.reduce((p, c) => [...p, ...c.teams], [])
|
|
112
|
+
.filter((t) => t && canPlayLeague(t));
|
|
113
|
+
|
|
114
|
+
if (HAS_NEXT_SEASON_PLAYOFF && GROUP_SIZE * 3 >= flatTeams.length) {
|
|
115
|
+
return calculateTeamsStandingForPlayoff(flatTeams, division);
|
|
116
|
+
}
|
|
117
|
+
return calculateTeamsStandingForLeagues(newStandings, division);
|
|
118
|
+
};
|
|
119
|
+
|
|
49
120
|
const forcastNextSeason = (flatTeams) => {
|
|
121
|
+
// debugger;
|
|
50
122
|
let groups = [];
|
|
51
123
|
let open = [];
|
|
52
124
|
let currentGroup = [];
|
|
125
|
+
let i = 0;
|
|
53
126
|
flatTeams.forEach((team) => {
|
|
54
127
|
if (!team) {
|
|
55
128
|
return;
|
|
56
129
|
}
|
|
57
|
-
|
|
130
|
+
// En playoff on n'a que les ligues A et B + open
|
|
131
|
+
if (!team.canChampionship || i >= 2) {
|
|
58
132
|
open.push(team);
|
|
59
133
|
return;
|
|
60
134
|
}
|
|
61
135
|
currentGroup.push(team);
|
|
62
136
|
|
|
137
|
+
if (currentGroup.length === GROUP_SIZE) {
|
|
138
|
+
groups = [...groups, currentGroup];
|
|
139
|
+
currentGroup = [];
|
|
140
|
+
++i;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
open = [...currentGroup, ...open];
|
|
144
|
+
|
|
145
|
+
if (open.length < GROUP_SIZE) {
|
|
146
|
+
const lastDivision = groups.pop();
|
|
147
|
+
if (lastDivision) {
|
|
148
|
+
open = [...lastDivision, ...open];
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
groups = [...groups, open];
|
|
152
|
+
return { hasPlayoffs: false, groups };
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const playoffNextSeason = (flatTeams) => {
|
|
156
|
+
let groups = [];
|
|
157
|
+
let open = [];
|
|
158
|
+
let currentGroup = [];
|
|
159
|
+
|
|
160
|
+
// Creation de groupe de 4
|
|
161
|
+
flatTeams.forEach((team) => {
|
|
162
|
+
if (!team) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Obligatoire pour les playoffs
|
|
166
|
+
currentGroup.push(team);
|
|
167
|
+
|
|
63
168
|
if (currentGroup.length === GROUP_SIZE) {
|
|
64
169
|
groups = [...groups, currentGroup];
|
|
65
170
|
currentGroup = [];
|
|
66
171
|
}
|
|
67
172
|
});
|
|
173
|
+
// Le reste est mis en open
|
|
68
174
|
open = [...currentGroup, ...open];
|
|
69
175
|
|
|
70
176
|
if (open.length < GROUP_SIZE) {
|
|
@@ -74,7 +180,12 @@ const forcastNextSeason = (flatTeams) => {
|
|
|
74
180
|
}
|
|
75
181
|
}
|
|
76
182
|
groups = [...groups, open];
|
|
77
|
-
|
|
183
|
+
|
|
184
|
+
if (HAS_NEXT_SEASON_PLAYOFF === false || groups.length < 3) {
|
|
185
|
+
return forcastNextSeason(flatTeams);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
return { hasPlayoffs: true, groups };
|
|
78
189
|
};
|
|
79
190
|
|
|
80
191
|
function round(r, teams) {
|
|
@@ -105,26 +216,32 @@ function tournament(teams) {
|
|
|
105
216
|
}
|
|
106
217
|
|
|
107
218
|
function hasCalendar(league) {
|
|
108
|
-
return
|
|
109
|
-
league.name !== LEAGUE_NAME.OPEN && league.name !== LEAGUE_NAME.FRIENDLY
|
|
110
|
-
);
|
|
219
|
+
return league.name !== GAME_TYPE.OPEN && league.name !== GAME_TYPE.FRIENDLY;
|
|
111
220
|
}
|
|
112
221
|
|
|
113
222
|
function sortLeagues(a, b) {
|
|
114
|
-
if (a.name < b.name || b.name ===
|
|
223
|
+
if (a.name < b.name || b.name === GAME_TYPE.FRIENDLY) {
|
|
115
224
|
return -1;
|
|
116
225
|
}
|
|
117
|
-
if (a.name > b.name || a.name ===
|
|
226
|
+
if (a.name > b.name || a.name === GAME_TYPE.FRIENDLY) {
|
|
118
227
|
return 1;
|
|
119
228
|
}
|
|
120
229
|
return 0;
|
|
121
230
|
}
|
|
122
231
|
|
|
232
|
+
function getWinner(game) {
|
|
233
|
+
// TODO
|
|
234
|
+
if (game.score1 > game.score2) {
|
|
235
|
+
return game.team1_id;
|
|
236
|
+
} else {
|
|
237
|
+
return game.team2_id;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
123
240
|
module.exports = {
|
|
124
|
-
|
|
241
|
+
getWinner,
|
|
125
242
|
calculateTeamsStandingForNextSeason,
|
|
126
|
-
forcastNextSeason,
|
|
127
243
|
hasCalendar,
|
|
128
|
-
|
|
244
|
+
playoffNextSeason,
|
|
129
245
|
sortLeagues,
|
|
246
|
+
tournament,
|
|
130
247
|
};
|
package/package.json
CHANGED
package/race.js
CHANGED
|
@@ -33,29 +33,29 @@ module.exports = {
|
|
|
33
33
|
range: 0,
|
|
34
34
|
cost: 60,
|
|
35
35
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
36
|
+
"lizardmen-chameleon": {
|
|
37
|
+
MA: 7,
|
|
38
|
+
ST: 2,
|
|
39
|
+
AG: 3,
|
|
40
|
+
AV: 7,
|
|
41
|
+
normal: "A",
|
|
42
|
+
double: "GPS",
|
|
43
|
+
normalCoach: "G",
|
|
44
|
+
icons: ["lizardmen-chameleon1"],
|
|
45
|
+
skills: [
|
|
46
|
+
SKILL_NAMES.DODGE,
|
|
47
|
+
SKILL_NAMES.ON_THE_BALL,
|
|
48
|
+
SKILL_NAMES.SHADOWING,
|
|
49
|
+
SKILL_NAMES.STUNTY,
|
|
50
|
+
],
|
|
51
|
+
badge: "lizardmen-career",
|
|
52
|
+
range: 1,
|
|
53
|
+
cost: 70,
|
|
54
|
+
},
|
|
55
55
|
"lizardmen-saurus": {
|
|
56
56
|
MA: 6,
|
|
57
57
|
ST: 4,
|
|
58
|
-
AG:
|
|
58
|
+
AG: 1,
|
|
59
59
|
AV: 9,
|
|
60
60
|
normal: "GS",
|
|
61
61
|
double: "A",
|
|
@@ -69,7 +69,7 @@ module.exports = {
|
|
|
69
69
|
"lizardmen-kroxigor": {
|
|
70
70
|
MA: 6,
|
|
71
71
|
ST: 5,
|
|
72
|
-
AG:
|
|
72
|
+
AG: 1,
|
|
73
73
|
AV: 9,
|
|
74
74
|
normal: "S",
|
|
75
75
|
double: "AG",
|
|
@@ -175,7 +175,7 @@ module.exports = {
|
|
|
175
175
|
icons: ["norse-yhetee1"],
|
|
176
176
|
skills: [
|
|
177
177
|
SKILL_NAMES.CLAW,
|
|
178
|
-
|
|
178
|
+
SKILL_NAMES.DISTURBING_PRESENCE,
|
|
179
179
|
SKILL_NAMES.FRENZY,
|
|
180
180
|
[SKILL_NAMES.LONER, 4],
|
|
181
181
|
SKILL_NAMES.UNCHANNELLED_FURY,
|
|
@@ -199,7 +199,7 @@ module.exports = {
|
|
|
199
199
|
skills: [SKILL_NAMES.DODGE],
|
|
200
200
|
badge: "amazon-career",
|
|
201
201
|
range: 0,
|
|
202
|
-
cost:
|
|
202
|
+
cost: 50,
|
|
203
203
|
},
|
|
204
204
|
"amazon-thrower": {
|
|
205
205
|
MA: 6,
|
package/skill.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const { distanceSquares } = require("./calcul");
|
|
2
|
+
const { hasStatusOnField } = require("./status");
|
|
1
3
|
const { getTime, TYPE_TIMER } = require("./time");
|
|
2
4
|
|
|
3
5
|
const BIG_GUY_LIMIT = 1;
|
|
@@ -7,6 +9,7 @@ const SPECIALIST_LIMIT = 6;
|
|
|
7
9
|
const SKILL_INFO_ACTIVE = "active";
|
|
8
10
|
const SKILL_INFO_INACTIVE = "inactive";
|
|
9
11
|
|
|
12
|
+
// Missing for races
|
|
10
13
|
const SKILL_NAMES = {
|
|
11
14
|
ACCURATE: "accurate",
|
|
12
15
|
ALWAYS_HUNGRY: "always-hungry",
|
|
@@ -24,6 +27,7 @@ const SKILL_NAMES = {
|
|
|
24
27
|
DAUNTLESS: "dauntless",
|
|
25
28
|
DEFENSIVE: "defensive",
|
|
26
29
|
DIRTY_PLAYER: "dirty-player",
|
|
30
|
+
DISTURBING_PRESENCE: "distrubing-presence",
|
|
27
31
|
DODGE: "dodge",
|
|
28
32
|
DUMP_OFF: "dump-off",
|
|
29
33
|
FEND: "fend",
|
|
@@ -38,6 +42,7 @@ const SKILL_NAMES = {
|
|
|
38
42
|
LONER: "loner",
|
|
39
43
|
MIGHTY_BLOW: "mighty-blow",
|
|
40
44
|
NERVES_OF_STEEL: "nerves-of-steel",
|
|
45
|
+
ON_THE_BALL: "on-the-ball",
|
|
41
46
|
PASS: "pass",
|
|
42
47
|
PILE_DRIVER: "pile-driver",
|
|
43
48
|
PREHENSILE_TAIL: "prehensile-tail",
|
|
@@ -47,6 +52,7 @@ const SKILL_NAMES = {
|
|
|
47
52
|
RIGHT_STUFF: "right-stuff",
|
|
48
53
|
RUNNING_PASS: "running-pass",
|
|
49
54
|
SAFE_PASS: "safe-pass",
|
|
55
|
+
SHADOWING: "shadowing",
|
|
50
56
|
SNEAKY_GIT: "sneaky-git",
|
|
51
57
|
SPECIALIST: "specialist",
|
|
52
58
|
SPRINT: "sprint",
|
|
@@ -98,6 +104,7 @@ const SKILLS = {
|
|
|
98
104
|
[SKILL_NAMES.DAUNTLESS]: SKILL_TYPE.GENERAL,
|
|
99
105
|
[SKILL_NAMES.DEFENSIVE]: SKILL_TYPE.AGILITY,
|
|
100
106
|
[SKILL_NAMES.DIRTY_PLAYER]: SKILL_TYPE.GENERAL,
|
|
107
|
+
[SKILL_NAMES.DISTURBING_PRESENCE]: SKILL_TYPE.MUTATION,
|
|
101
108
|
[SKILL_NAMES.DODGE]: SKILL_TYPE.AGILITY,
|
|
102
109
|
[SKILL_NAMES.DUMP_OFF]: SKILL_TYPE.PASSING,
|
|
103
110
|
[SKILL_NAMES.FEND]: SKILL_TYPE.GENERAL,
|
|
@@ -112,6 +119,7 @@ const SKILLS = {
|
|
|
112
119
|
[SKILL_NAMES.LONER]: SKILL_TYPE.EXTRAORDINARY,
|
|
113
120
|
[SKILL_NAMES.MIGHTY_BLOW]: SKILL_TYPE.STRENGTH,
|
|
114
121
|
[SKILL_NAMES.NERVES_OF_STEEL]: SKILL_TYPE.PASSING,
|
|
122
|
+
[SKILL_NAMES.ON_THE_BALL]: SKILL_TYPE.PASSING,
|
|
115
123
|
[SKILL_NAMES.PASS]: SKILL_TYPE.PASSING,
|
|
116
124
|
[SKILL_NAMES.PILE_DRIVER]: SKILL_TYPE.STRENGTH,
|
|
117
125
|
[SKILL_NAMES.PREHENSILE_TAIL]: SKILL_TYPE.MUTATION,
|
|
@@ -121,6 +129,7 @@ const SKILLS = {
|
|
|
121
129
|
[SKILL_NAMES.RIGHT_STUFF]: SKILL_TYPE.EXTRAORDINARY,
|
|
122
130
|
[SKILL_NAMES.RUNNING_PASS]: SKILL_TYPE.PASSING,
|
|
123
131
|
[SKILL_NAMES.SAFE_PASS]: SKILL_TYPE.PASSING,
|
|
132
|
+
[SKILL_NAMES.SHADOWING]: SKILL_TYPE.GENERAL,
|
|
124
133
|
[SKILL_NAMES.SNEAKY_GIT]: SKILL_TYPE.AGILITY,
|
|
125
134
|
[SKILL_NAMES.SPECIALIST]: SKILL_TYPE.EXTRAORDINARY,
|
|
126
135
|
[SKILL_NAMES.SPRINT]: SKILL_TYPE.AGILITY,
|
|
@@ -211,6 +220,7 @@ const isActivableSkills = (skill) => {
|
|
|
211
220
|
SKILL_NAMES.PILE_DRIVER,
|
|
212
221
|
SKILL_NAMES.TENTACLES,
|
|
213
222
|
SKILL_NAMES.WRESTLE,
|
|
223
|
+
SKILL_NAMES.SHADOWING,
|
|
214
224
|
];
|
|
215
225
|
return activables.includes(skill);
|
|
216
226
|
};
|
|
@@ -254,6 +264,30 @@ function getSkillLimitSizeTeam(player, teamPlayers) {
|
|
|
254
264
|
return null;
|
|
255
265
|
}
|
|
256
266
|
|
|
267
|
+
/*
|
|
268
|
+
DISTURBING PRESENCE
|
|
269
|
+
When an opposition player performs either a
|
|
270
|
+
Pass action,
|
|
271
|
+
a Throw Team- mate action
|
|
272
|
+
or a Throw Bomb Special action,
|
|
273
|
+
or attempts to either interfere with a pass
|
|
274
|
+
or to catch the ball,
|
|
275
|
+
they must apply a -1 modifier to the test for each player on your team with this Skill
|
|
276
|
+
that is within three squares of them,
|
|
277
|
+
even if the player with this Skill is Prone,
|
|
278
|
+
Stunned or has lost their Tackle Zone. */
|
|
279
|
+
function getDisturbingPresenceMalus(player, players) {
|
|
280
|
+
const malus = players.filter((p) => {
|
|
281
|
+
return (
|
|
282
|
+
p.teamId !== player.teamId &&
|
|
283
|
+
hasStatusOnField(p) &&
|
|
284
|
+
hasSkill(p, SKILL_NAMES.DISTURBING_PRESENCE) &&
|
|
285
|
+
distanceSquares(player, p, 3)
|
|
286
|
+
);
|
|
287
|
+
}).length;
|
|
288
|
+
return malus;
|
|
289
|
+
}
|
|
290
|
+
|
|
257
291
|
module.exports = {
|
|
258
292
|
BIG_GUY_LIMIT,
|
|
259
293
|
getPlayersWithSkill,
|
|
@@ -268,4 +302,5 @@ module.exports = {
|
|
|
268
302
|
SKILL_NAMES,
|
|
269
303
|
SKILLS,
|
|
270
304
|
useSkill,
|
|
305
|
+
getDisturbingPresenceMalus,
|
|
271
306
|
};
|
package/skillCoach.js
CHANGED
|
@@ -13,7 +13,7 @@ const SKILL_COACH_TYPE = {
|
|
|
13
13
|
// TODO: add text translation when add a skill
|
|
14
14
|
const COACH_SKILLS = {
|
|
15
15
|
[SKILL_COACH_NAMES.SPONSOR]: SKILL_COACH_TYPE.GENERAL,
|
|
16
|
-
[SKILL_COACH_NAMES.SPY]: SKILL_COACH_TYPE.GENERAL,
|
|
16
|
+
// [SKILL_COACH_NAMES.SPY]: SKILL_COACH_TYPE.GENERAL, // If reactivate, check getCoachSkill hotfix
|
|
17
17
|
[SKILL_COACH_NAMES.THREATENING]: SKILL_COACH_TYPE.GENERAL,
|
|
18
18
|
};
|
|
19
19
|
|
|
@@ -23,6 +23,10 @@ function shouldDisplayInfoInName(skillId) {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
function getCoachSkill(player, skillId) {
|
|
26
|
+
if (skillId === SKILL_COACH_NAMES.SPY) {
|
|
27
|
+
// Hotfix
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
26
30
|
if (!COACH_SKILLS.hasOwnProperty(skillId)) {
|
|
27
31
|
throw `Skill '${skillId}' does not exist`;
|
|
28
32
|
}
|