enefel 1.0.98 → 1.0.101

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 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 { hasSkill, SKILL_NAMES } = require("./skill");
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
- if (player.current_AG - zdt > bestAG) {
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,81 @@
1
- const { isTeamActive } = require("./state");
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;
4
6
 
5
- const LEAGUE_NAME = {
6
- OPEN: "open",
7
- FRIENDLY: "friendly",
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
+ if (!nextDivision) {
32
+ break;
33
+ }
34
+ const currentDivisionLastTeam =
35
+ currentDivision.teams[currentDivision.teams.length - 1];
36
+
37
+ // Le dernier de la ligue A va remplacer premier de l'open
38
+ // Le dernier de la ligue B va remplacer le second de l'open
39
+ const nextDivisionFirstTeam = nextDivision.teams[isLeagueB ? 1 : 0];
40
+
41
+ currentDivision.teams[currentDivision.teams.length - 1] =
42
+ nextDivisionFirstTeam;
43
+
44
+ nextDivision.teams[isLeagueB ? 1 : 0] = currentDivisionLastTeam;
45
+ }
46
+ }
47
+
48
+ // Les ligues A est B sont classé par ELO
49
+ const flatedTeams = standings.reduce((p, c) => [...p, ...c.teams], []);
50
+ if (!flatedTeams || flatedTeams.length === 0) {
51
+ return [];
52
+ }
53
+ const size = GROUP_SIZE * 2;
54
+ for (i = 0; i < size; i++) {
55
+ for (j = i + 1; j < size; j++) {
56
+ if (!flatedTeams[j] || !flatedTeams[i]) {
57
+ continue;
58
+ }
59
+ if (flatedTeams[j].elo > flatedTeams[i].elo) {
60
+ let temp = flatedTeams[i];
61
+ flatedTeams[i] = flatedTeams[j];
62
+ flatedTeams[j] = temp;
63
+ }
64
+ }
65
+ }
66
+ // 0 1 2 3 4 5 6 7
67
+ // 0 2 4 6 1 3 5 7
68
+ let temp = flatedTeams[1];
69
+ flatedTeams[1] = flatedTeams[4];
70
+ flatedTeams[4] = temp;
71
+ temp = flatedTeams[3];
72
+ flatedTeams[3] = flatedTeams[6];
73
+ flatedTeams[6] = temp;
74
+
75
+ return flatedTeams;
8
76
  };
9
77
 
10
- const calculateTeamsStandingForNextSeason = (division) => {
11
- // Standing division should be sorted (1, 2, 3, ... , open)
12
- const newStandings = JSON.parse(JSON.stringify(division));
78
+ const calculateTeamsStandingForLeagues = (newStandings, division) => {
13
79
  for (let i = 0; i < division.length - 1; ++i) {
14
80
  const currentDivision = newStandings[i];
15
81
  const nextDivision = newStandings[i + 1];
@@ -18,10 +84,8 @@ const calculateTeamsStandingForNextSeason = (division) => {
18
84
  currentDivision.teams[currentDivision.teams.length - 1];
19
85
 
20
86
  let indexNextDivisionFirstTeam = 0;
21
- if (nextDivision.name === LEAGUE_NAME.FRIENDLY) {
22
- continue;
23
- }
24
- if (nextDivision.name === LEAGUE_NAME.OPEN) {
87
+
88
+ if (nextDivision.name === GAME_TYPE.OPEN) {
25
89
  // To avoid some teams block the open, we take the first team with canChampionship
26
90
  indexNextDivisionFirstTeam = nextDivision.teams.findIndex(
27
91
  (t) => t.canChampionship
@@ -33,28 +97,47 @@ const calculateTeamsStandingForNextSeason = (division) => {
33
97
  const nextDivisionFirstTeam =
34
98
  nextDivision.teams[indexNextDivisionFirstTeam];
35
99
 
36
- currentDivision.teams[
37
- currentDivision.teams.length - 1
38
- ] = nextDivisionFirstTeam;
100
+ currentDivision.teams[currentDivision.teams.length - 1] =
101
+ nextDivisionFirstTeam;
39
102
 
40
103
  nextDivision.teams[indexNextDivisionFirstTeam] = currentDivisionLastTeam;
41
104
  }
42
105
  const flatTeams = newStandings
43
106
  .reduce((p, c) => [...p, ...c.teams], [])
44
- .filter((t) => t && isTeamActive(t.state));
107
+ .filter((t) => t && canPlayLeague(t));
45
108
 
46
109
  return flatTeams;
47
110
  };
48
111
 
112
+ const calculateTeamsStandingForNextSeason = (division) => {
113
+ division = division.filter(
114
+ (d) => d.name !== GAME_TYPE.FRIENDLY && d.name !== GAME_TYPE.PLAYOFF
115
+ );
116
+ // Standing division should be sorted (playoff, 1, 2, 3, ... , open)
117
+ const newStandings = JSON.parse(JSON.stringify(division));
118
+
119
+ const flatTeams = newStandings
120
+ .reduce((p, c) => [...p, ...c.teams], [])
121
+ .filter((t) => t && canPlayLeague(t));
122
+
123
+ if (HAS_NEXT_SEASON_PLAYOFF && GROUP_SIZE * 3 >= flatTeams.length) {
124
+ return calculateTeamsStandingForPlayoff(flatTeams, division);
125
+ }
126
+ return calculateTeamsStandingForLeagues(newStandings, division);
127
+ };
128
+
49
129
  const forcastNextSeason = (flatTeams) => {
130
+ // debugger;
50
131
  let groups = [];
51
132
  let open = [];
52
133
  let currentGroup = [];
134
+ let i = 0;
53
135
  flatTeams.forEach((team) => {
54
136
  if (!team) {
55
137
  return;
56
138
  }
57
- if (!team.canChampionship) {
139
+ // En playoff on n'a que les ligues A et B + open
140
+ if (!team.canChampionship || i >= 2) {
58
141
  open.push(team);
59
142
  return;
60
143
  }
@@ -63,6 +146,7 @@ const forcastNextSeason = (flatTeams) => {
63
146
  if (currentGroup.length === GROUP_SIZE) {
64
147
  groups = [...groups, currentGroup];
65
148
  currentGroup = [];
149
+ ++i;
66
150
  }
67
151
  });
68
152
  open = [...currentGroup, ...open];
@@ -74,7 +158,43 @@ const forcastNextSeason = (flatTeams) => {
74
158
  }
75
159
  }
76
160
  groups = [...groups, open];
77
- return groups;
161
+ return { hasPlayoffs: false, groups };
162
+ };
163
+
164
+ const playoffNextSeason = (flatTeams) => {
165
+ let groups = [];
166
+ let open = [];
167
+ let currentGroup = [];
168
+
169
+ // Creation de groupe de 4
170
+ flatTeams.forEach((team) => {
171
+ if (!team) {
172
+ return;
173
+ }
174
+ // Obligatoire pour les playoffs
175
+ currentGroup.push(team);
176
+
177
+ if (currentGroup.length === GROUP_SIZE) {
178
+ groups = [...groups, currentGroup];
179
+ currentGroup = [];
180
+ }
181
+ });
182
+ // Le reste est mis en open
183
+ open = [...currentGroup, ...open];
184
+
185
+ if (open.length < GROUP_SIZE) {
186
+ const lastDivision = groups.pop();
187
+ if (lastDivision) {
188
+ open = [...lastDivision, ...open];
189
+ }
190
+ }
191
+ groups = [...groups, open];
192
+
193
+ if (HAS_NEXT_SEASON_PLAYOFF === false || groups.length < 3) {
194
+ return forcastNextSeason(flatTeams);
195
+ }
196
+
197
+ return { hasPlayoffs: true, groups };
78
198
  };
79
199
 
80
200
  function round(r, teams) {
@@ -105,26 +225,32 @@ function tournament(teams) {
105
225
  }
106
226
 
107
227
  function hasCalendar(league) {
108
- return (
109
- league.name !== LEAGUE_NAME.OPEN && league.name !== LEAGUE_NAME.FRIENDLY
110
- );
228
+ return league.name !== GAME_TYPE.OPEN && league.name !== GAME_TYPE.FRIENDLY;
111
229
  }
112
230
 
113
231
  function sortLeagues(a, b) {
114
- if (a.name < b.name || b.name === LEAGUE_NAME.FRIENDLY) {
232
+ if (a.name < b.name || b.name === GAME_TYPE.FRIENDLY) {
115
233
  return -1;
116
234
  }
117
- if (a.name > b.name || a.name === LEAGUE_NAME.FRIENDLY) {
235
+ if (a.name > b.name || a.name === GAME_TYPE.FRIENDLY) {
118
236
  return 1;
119
237
  }
120
238
  return 0;
121
239
  }
122
240
 
241
+ function getWinner(game) {
242
+ // TODO
243
+ if (game.score1 > game.score2) {
244
+ return game.team1_id;
245
+ } else {
246
+ return game.team2_id;
247
+ }
248
+ }
123
249
  module.exports = {
124
- LEAGUE_NAME,
250
+ getWinner,
125
251
  calculateTeamsStandingForNextSeason,
126
- forcastNextSeason,
127
252
  hasCalendar,
128
- tournament,
253
+ playoffNextSeason,
129
254
  sortLeagues,
255
+ tournament,
130
256
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "enefel",
3
- "version": "1.0.98",
3
+ "version": "1.0.101",
4
4
  "main": "index.js",
5
5
  "author": "Manest",
6
6
  "license": "MIT",
package/race.js CHANGED
@@ -33,25 +33,25 @@ module.exports = {
33
33
  range: 0,
34
34
  cost: 60,
35
35
  },
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
- // },
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,
@@ -175,7 +175,7 @@ module.exports = {
175
175
  icons: ["norse-yhetee1"],
176
176
  skills: [
177
177
  SKILL_NAMES.CLAW,
178
- // SKILL_NAMES.DISTURBING_PRESENCE,
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: 75,
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
  };