Skip to content

Commit

Permalink
fix: better hero ability & level calculation (#75)
Browse files Browse the repository at this point in the history
* fix: better hero level calculation

* test: add test for hero ability calculation

* improvement: HeroAbilityCalculator implementation

* improvement: use hero ability calculator

* style: fix prettier

* improvement: add all ultimates to ultimate set

* refactor: rename new test file to be included in tests
  • Loading branch information
PBug90 authored Dec 10, 2021
1 parent bebbe0a commit 0f79376
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 2 deletions.
9 changes: 7 additions & 2 deletions src/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { items, units, buildings, upgrades, abilityToHero } from "./mappings";
import { Race, ItemID } from "./types";
import { TransferResourcesActionWithPlayer } from "./W3GReplay";
import { Action } from "./parsers/ActionParser";
import { inferHeroAbilityLevelsFromAbilityOrder } from "./inferHeroAbilityLevelsFromAbilityOrder";

const isRightclickAction = (input: number[]) =>
input[0] === 0x03 && input[1] === 0;
Expand All @@ -18,6 +19,9 @@ export const reduceHeroes = (heroCollector: {
return Object.values(heroCollector)
.sort((h1, h2) => h1.order - h2.order)
.reduce((aggregator, hero) => {
hero.abilities = inferHeroAbilityLevelsFromAbilityOrder(
hero.abilityOrder
);
hero.level = Object.values(hero.abilities).reduce(
(prev, curr) => prev + curr,
0
Expand All @@ -28,13 +32,13 @@ export const reduceHeroes = (heroCollector: {
}, [] as Omit<HeroInfo, "order">[]);
};

interface Ability {
export interface Ability {
type: "ability";
time: number;
value: string;
}

interface Retraining {
export interface Retraining {
type: "retraining";
time: number;
}
Expand Down Expand Up @@ -67,6 +71,7 @@ class Player {
summary: { [key: string]: number };
order: { id: string; ms: number }[];
};

buildings: {
summary: { [key: string]: number };
order: { id: string; ms: number }[];
Expand Down
51 changes: 51 additions & 0 deletions src/inferHeroAbilityLevelsFromAbilityOrder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Ability, Retraining } from "./Player";

const ultimates = new Set<string>()
.add("AEtq")
.add("AEme")
.add("AEsf")
.add("AEsv")
.add("AOww")
.add("AOeq")
.add("AOre")
.add("AOvd")
.add("AUan")
.add("AUin")
.add("AUdd")
.add("AUls")
.add("ANef")
.add("ANch")
.add("ANto")
.add("ANdo")
.add("ANst")
.add("ANrg")
.add("ANg1")
.add("ANg2")
.add("ANg3")
.add("ANvc")
.add("ANtm")
.add("AHmt")
.add("AHav")
.add("AHre")
.add("AHpx");

export function inferHeroAbilityLevelsFromAbilityOrder(
abilityOrder: (Ability | Retraining)[]
): { [key: string]: number } {
let abilities: { [key: string]: number } = {};
for (const ability of abilityOrder) {
if (ability.type === "ability") {
if (ultimates.has(ability.value) && abilities[ability.value] === 1) {
continue;
}
abilities[ability.value] = abilities[ability.value] || 0;
if (abilities[ability.value] < 3) {
abilities[ability.value]++;
}
}
if (ability.type === "retraining") {
abilities = {};
}
}
return abilities;
}
108 changes: 108 additions & 0 deletions test/inferHeroAbilityLevelsFromAbilityOrder.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { inferHeroAbilityLevelsFromAbilityOrder } from "../src/inferHeroAbilityLevelsFromAbilityOrder";
import { Ability } from "../src/Player";

const input: Ability[] = [
{
type: "ability",
time: 126467,
value: "AEfn",
},
{
type: "ability",
time: 178541,
value: "AEer",
},
{
type: "ability",
time: 534905,
value: "AEfn",
},
{
type: "ability",
time: 1016408,
value: "AEer",
},
{
type: "ability",
time: 1907059,
value: "AEer",
},
{
type: "ability",
time: 2091683,
value: "AEtq",
},
{
type: "ability",
time: 2093068,
value: "AEtq",
},
{
type: "ability",
time: 2093226,
value: "AEtq",
},
{
type: "ability",
time: 2093357,
value: "AEtq",
},
{
type: "ability",
time: 2093505,
value: "AEtq",
},
{
type: "ability",
time: 2093617,
value: "AEtq",
},
{
type: "ability",
time: 2093738,
value: "AEtq",
},
{
type: "ability",
time: 2093847,
value: "AEtq",
},
{
type: "ability",
time: 2094002,
value: "AEtq",
},
{
type: "ability",
time: 2094137,
value: "AEtq",
},
{
type: "ability",
time: 2094271,
value: "AEtq",
},
{
type: "ability",
time: 2094393,
value: "AEtq",
},
{
type: "ability",
time: 2094526,
value: "AEtq",
},
{
type: "ability",
time: 2094671,
value: "AEtq",
},
];

it("correctly infers that KOTG only has tranquility level 1", () => {
expect(inferHeroAbilityLevelsFromAbilityOrder(input)).toEqual({
AEfn: 2,
AEer: 3,
AEtq: 1,
});
});
Binary file added test/replays/132/706266088.w3g
Binary file not shown.
5 changes: 5 additions & 0 deletions test/replays/132/replays.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,8 @@ it("should handle a netease replay with rogue playerId 3 CommandDataBlocks corre
const test = await Parser.parse(path.resolve(__dirname, "1582070968.nwg"));
expect(test.players).toMatchSnapshot();
});

it("should parse kotg as level 6", async () => {
const test = await Parser.parse(path.resolve(__dirname, "706266088.w3g"));
expect(test.players[1].heroes[0].level).toBe(6);
});

0 comments on commit 0f79376

Please sign in to comment.