Skip to content

Commit

Permalink
Merge cc979cd into 333bfe2
Browse files Browse the repository at this point in the history
  • Loading branch information
OGoodness committed Feb 16, 2021
2 parents 333bfe2 + cc979cd commit e3d777f
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 7 deletions.
Binary file added slp/consistencyTest/BowsVDK-SB-63.slp
Binary file not shown.
Binary file added slp/consistencyTest/FalcVBows-5UB-67.slp
Binary file not shown.
Binary file added slp/consistencyTest/GanonVDK-5UB-73.slp
Binary file not shown.
Binary file added slp/consistencyTest/KirbyVDK-Neutral-17.slp
Binary file not shown.
Binary file added slp/consistencyTest/MewTwoVDK-SB-42.slp
Binary file not shown.
Binary file added slp/consistencyTest/PichuVSelf-All-22.slp
Binary file not shown.
Binary file added slp/consistencyTest/Puff-MagnifyingGlass-10.slp
Binary file not shown.
Binary file added slp/consistencyTest/YoshiVDK-Egg-13.slp
Binary file not shown.
17 changes: 14 additions & 3 deletions src/stats/combos.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import _ from "lodash";
import { FrameEntryType, FramesType, PostFrameUpdateType } from "../types";
import { MoveLandedType, ComboType, PlayerIndexedType } from "./common";
import { isDamaged, isGrabbed, calcDamageTaken, isTeching, didLoseStock, Timers, isDown, isDead } from "./common";
import {
isDamaged,
isGrabbed,
isCommandGrabbed,
calcDamageTaken,
isTeching,
didLoseStock,
Timers,
isDown,
isDead,
} from "./common";
import { StatComputer } from "./stats";

interface ComboState {
Expand Down Expand Up @@ -66,6 +76,7 @@ function handleComboCompute(
const oppActionStateId = opponentFrame.actionStateId!;
const opntIsDamaged = isDamaged(oppActionStateId);
const opntIsGrabbed = isGrabbed(oppActionStateId);
const opntIsCommandGrabbed = isCommandGrabbed(oppActionStateId);
const opntDamageTaken = prevOpponentFrame ? calcDamageTaken(opponentFrame, prevOpponentFrame) : 0;

// Keep track of whether actionState changes after a hit. Used to compute move count
Expand All @@ -84,7 +95,7 @@ function handleComboCompute(

// If opponent took damage and was put in some kind of stun this frame, either
// start a combo or count the moves for the existing combo
if (opntIsDamaged || opntIsGrabbed) {
if (opntIsDamaged || opntIsGrabbed || opntIsCommandGrabbed) {
if (!state.combo) {
state.combo = {
playerIndex: indices.playerIndex,
Expand Down Expand Up @@ -142,7 +153,7 @@ function handleComboCompute(
state.combo.currentPercent = opponentFrame.percent ?? 0;
}

if (opntIsDamaged || opntIsGrabbed || opntIsTeching || opntIsDowned || opntIsDying) {
if (opntIsDamaged || opntIsGrabbed || opntIsCommandGrabbed || opntIsTeching || opntIsDowned || opntIsDying) {
// If opponent got grabbed or damaged, reset the reset counter
state.resetCounter = 0;
} else {
Expand Down
22 changes: 21 additions & 1 deletion src/stats/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,17 @@ export enum State {
FALL_BACKWARD = 0x1f,
GRAB = 0xd4,
CLIFF_CATCH = 0xfc,
DAMAGE_FALL = 0x26,

// Command Grabs
COMMAND_GRAB_RANGE1_START = 0x10a,
COMMAND_GRAB_RANGE1_END = 0x130,

COMMAND_GRAB_RANGE2_START = 0x147,
COMMAND_GRAB_RANGE2_END = 0x153,

COMMAND_GRAB_RANGE3_START = 0x177,
COMMAND_GRAB_RANGE3_END = 0x17e,
}

export const Timers = {
Expand Down Expand Up @@ -189,13 +200,22 @@ export function isDown(state: number): boolean {
}

export function isDamaged(state: number): boolean {
return state >= State.DAMAGE_START && state <= State.DAMAGE_END;
return (state >= State.DAMAGE_START && state <= State.DAMAGE_END) || state === State.DAMAGE_FALL;
}

export function isGrabbed(state: number): boolean {
return state >= State.CAPTURE_START && state <= State.CAPTURE_END;
}

// TODO: Find better implementation of 3 seperate ranges
export function isCommandGrabbed(state: number): boolean {
return (
(state >= State.COMMAND_GRAB_RANGE1_START && state <= State.COMMAND_GRAB_RANGE1_END) ||
(state >= State.COMMAND_GRAB_RANGE2_START && state <= State.COMMAND_GRAB_RANGE2_END) ||
(state >= State.COMMAND_GRAB_RANGE3_START && state <= State.COMMAND_GRAB_RANGE3_END)
);
}

export function isDead(state: number): boolean {
return state >= State.DYING_START && state <= State.DYING_END;
}
Expand Down
7 changes: 4 additions & 3 deletions src/stats/conversions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _ from "lodash";
import { FrameEntryType, FramesType, PostFrameUpdateType } from "../types";
import { MoveLandedType, ConversionType, PlayerIndexedType } from "./common";
import { isDamaged, isGrabbed, calcDamageTaken, isInControl, didLoseStock, Timers } from "./common";
import { isDamaged, isGrabbed, isCommandGrabbed, calcDamageTaken, isInControl, didLoseStock, Timers } from "./common";
import { StatComputer } from "./stats";

interface PlayerConversionState {
Expand Down Expand Up @@ -113,6 +113,7 @@ function handleConversionCompute(
const oppActionStateId = opponentFrame.actionStateId!;
const opntIsDamaged = isDamaged(oppActionStateId);
const opntIsGrabbed = isGrabbed(oppActionStateId);
const opntIsCommandGrabbed = isCommandGrabbed(oppActionStateId);
const opntDamageTaken = prevOpponentFrame ? calcDamageTaken(opponentFrame, prevOpponentFrame) : 0;

// Keep track of whether actionState changes after a hit. Used to compute move count
Expand All @@ -131,7 +132,7 @@ function handleConversionCompute(

// If opponent took damage and was put in some kind of stun this frame, either
// start a conversion or
if (opntIsDamaged || opntIsGrabbed) {
if (opntIsDamaged || opntIsGrabbed || opntIsCommandGrabbed) {
if (!state.conversion) {
state.conversion = {
playerIndex: indices.playerIndex,
Expand Down Expand Up @@ -188,7 +189,7 @@ function handleConversionCompute(
state.conversion.currentPercent = opponentFrame.percent ?? 0;
}

if (opntIsDamaged || opntIsGrabbed) {
if (opntIsDamaged || opntIsGrabbed || opntIsCommandGrabbed) {
// If opponent got grabbed or damaged, reset the reset counter
state.resetCounter = 0;
}
Expand Down
115 changes: 115 additions & 0 deletions test/stats.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,119 @@ describe("when calculating stats", () => {
expect(p2Success).toBe(5);
expect(p2Fail).toBe(4);
});
it("accounts for Blast Zone Magnifying Glass", () => {
const game = new SlippiGame("slp/consistencyTest/Puff-MagnifyingGlass-10.slp");
const stats = game.getStats();
const puff = stats.overall[0]
let totalDamagePuffDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === puff.playerIndex ){
totalDamagePuffDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamagePuffDealt).toBe(puff.totalDamage);
expect(puff.killCount).toBe(0);
expect(puff.conversionCount).toBe(0);
});
it("accounts for Pichu Self Harm", () => {
const game = new SlippiGame("slp/consistencyTest/PichuVSelf-All-22.slp");
const stats = game.getStats();
const pichu = stats.overall[0]
let totalDamagePichuDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === pichu.playerIndex ){
totalDamagePichuDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamagePichuDealt).toBe(pichu.totalDamage);
expect(pichu.killCount).toBe(0);
expect(pichu.conversionCount).toBe(3);
});
describe("When Handling Command Grabs", () => {
it("accounts for Bowser's Command Grab", () => {
const game = new SlippiGame("slp/consistencyTest/BowsVDK-SB-63.slp");
const stats = game.getStats();
const bowser = stats.overall[0]
let totalDamageBowserDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === bowser.playerIndex ){
totalDamageBowserDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamageBowserDealt).toBe(bowser.totalDamage);
expect(bowser.killCount).toBe(0);
expect(bowser.conversionCount).toBe(3);
});
it("accounts for Falcon's Command Grab", () => {
const game = new SlippiGame("slp/consistencyTest/FalcVBows-5UB-67.slp");
const stats = game.getStats();
const falcon = stats.overall[0]
let totalDamageFalconDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === falcon.playerIndex ){
totalDamageFalconDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamageFalconDealt).toBe(falcon.totalDamage);
expect(falcon.killCount).toBe(0);
expect(falcon.conversionCount).toBe(3);
});
it("accounts for Ganon's Command Grab", () => {
const game = new SlippiGame("slp/consistencyTest/GanonVDK-5UB-73.slp");
const stats = game.getStats();
const ganon = stats.overall[0]
let totalDamageGanonDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === ganon.playerIndex ){
totalDamageGanonDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamageGanonDealt).toBe(ganon.totalDamage);
expect(ganon.killCount).toBe(0);
expect(ganon.conversionCount).toBe(5);
});
it("accounts for Kirby's Command Grab", () => {
const game = new SlippiGame("slp/consistencyTest/KirbyVDK-Neutral-17.slp");
const stats = game.getStats();
const kirby = stats.overall[0]
let totalDamageKirbyDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === kirby.playerIndex ){
totalDamageKirbyDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamageKirbyDealt).toBe(kirby.totalDamage);
expect(kirby.killCount).toBe(0);
expect(kirby.conversionCount).toBe(3);
});
it("accounts for Yoshi's Command Grab", () => {
const game = new SlippiGame("slp/consistencyTest/YoshiVDK-Egg-13.slp");
const stats = game.getStats();
const yoshi = stats.overall[0]
let totalDamageYoshiDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === yoshi.playerIndex ){
totalDamageYoshiDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamageYoshiDealt).toBe(yoshi.totalDamage);
expect(yoshi.killCount).toBe(0);
expect(yoshi.conversionCount).toBe(2);
});
it("accounts for MewTwo's Command Grab", () => {
const game = new SlippiGame("slp/consistencyTest/MewTwoVDK-SB-42.slp");
const stats = game.getStats();
const mewTwo = stats.overall[0]
let totalDamageMewTwoDealt = 0
stats.conversions.forEach( conversion => {
if(conversion.playerIndex === mewTwo.playerIndex ){
totalDamageMewTwoDealt += conversion.moves.reduce((total, move) => total + move.damage, 0)
}
})
expect(totalDamageMewTwoDealt).toBe(mewTwo.totalDamage);
expect(mewTwo.killCount).toBe(0);
expect(mewTwo.conversionCount).toBe(1);
});

});
});

0 comments on commit e3d777f

Please sign in to comment.