finish type coverage functionality

This commit is contained in:
Jeff Colombo 2019-03-13 01:28:56 -04:00
parent ca3629f255
commit 2100315c80
13 changed files with 535 additions and 215 deletions

112
dist/app.css vendored
View File

@ -267,91 +267,145 @@
background-color: #a8a878; }
.TypeIndicator__pokemonType__3MOQI.normal::after {
box-shadow: 0 -4px #a8a878, 0 -8px, 4px 0 #a8a878, 4px -4px, 8px 0, 0 4px #a8a878, 0 8px, -4px 0 #a8a878, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.normal.outline {
color: #a8a878;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.fighting {
color: #fff;
background-color: #c03028; }
.TypeIndicator__pokemonType__3MOQI.fighting::after {
box-shadow: 0 -4px #c03028, 0 -8px, 4px 0 #c03028, 4px -4px, 8px 0, 0 4px #c03028, 0 8px, -4px 0 #c03028, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.fighting.outline {
color: #c03028;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.flying {
color: #fff;
background-color: #a890f0; }
.TypeIndicator__pokemonType__3MOQI.flying::after {
box-shadow: 0 -4px #a890f0, 0 -8px, 4px 0 #a890f0, 4px -4px, 8px 0, 0 4px #a890f0, 0 8px, -4px 0 #a890f0, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.flying.outline {
color: #a890f0;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.poison {
color: #fff;
background-color: #a040a0; }
.TypeIndicator__pokemonType__3MOQI.poison::after {
box-shadow: 0 -4px #a040a0, 0 -8px, 4px 0 #a040a0, 4px -4px, 8px 0, 0 4px #a040a0, 0 8px, -4px 0 #a040a0, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.poison.outline {
color: #a040a0;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.ground {
color: #fff;
background-color: #e0c068; }
.TypeIndicator__pokemonType__3MOQI.ground::after {
box-shadow: 0 -4px #e0c068, 0 -8px, 4px 0 #e0c068, 4px -4px, 8px 0, 0 4px #e0c068, 0 8px, -4px 0 #e0c068, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.ground.outline {
color: #e0c068;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.rock {
color: #fff;
background-color: #b8a038; }
.TypeIndicator__pokemonType__3MOQI.rock::after {
box-shadow: 0 -4px #b8a038, 0 -8px, 4px 0 #b8a038, 4px -4px, 8px 0, 0 4px #b8a038, 0 8px, -4px 0 #b8a038, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.rock.outline {
color: #b8a038;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.bug {
color: #fff;
background-color: #a8b820; }
.TypeIndicator__pokemonType__3MOQI.bug::after {
box-shadow: 0 -4px #a8b820, 0 -8px, 4px 0 #a8b820, 4px -4px, 8px 0, 0 4px #a8b820, 0 8px, -4px 0 #a8b820, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.bug.outline {
color: #a8b820;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.ghost {
color: #fff;
background-color: #705898; }
.TypeIndicator__pokemonType__3MOQI.ghost::after {
box-shadow: 0 -4px #705898, 0 -8px, 4px 0 #705898, 4px -4px, 8px 0, 0 4px #705898, 0 8px, -4px 0 #705898, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.ghost.outline {
color: #705898;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.steel {
color: #fff;
background-color: #b8b8d0; }
.TypeIndicator__pokemonType__3MOQI.steel::after {
box-shadow: 0 -4px #b8b8d0, 0 -8px, 4px 0 #b8b8d0, 4px -4px, 8px 0, 0 4px #b8b8d0, 0 8px, -4px 0 #b8b8d0, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.steel.outline {
color: #b8b8d0;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.fire {
color: #fff;
background-color: #f08030; }
.TypeIndicator__pokemonType__3MOQI.fire::after {
box-shadow: 0 -4px #f08030, 0 -8px, 4px 0 #f08030, 4px -4px, 8px 0, 0 4px #f08030, 0 8px, -4px 0 #f08030, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.fire.outline {
color: #f08030;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.water {
color: #fff;
background-color: #6890f0; }
.TypeIndicator__pokemonType__3MOQI.water::after {
box-shadow: 0 -4px #6890f0, 0 -8px, 4px 0 #6890f0, 4px -4px, 8px 0, 0 4px #6890f0, 0 8px, -4px 0 #6890f0, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.water.outline {
color: #6890f0;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.grass {
color: #fff;
background-color: #78c850; }
.TypeIndicator__pokemonType__3MOQI.grass::after {
box-shadow: 0 -4px #78c850, 0 -8px, 4px 0 #78c850, 4px -4px, 8px 0, 0 4px #78c850, 0 8px, -4px 0 #78c850, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.grass.outline {
color: #78c850;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.electric {
color: #fff;
background-color: #f8d030; }
.TypeIndicator__pokemonType__3MOQI.electric::after {
box-shadow: 0 -4px #f8d030, 0 -8px, 4px 0 #f8d030, 4px -4px, 8px 0, 0 4px #f8d030, 0 8px, -4px 0 #f8d030, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.electric.outline {
color: #f8d030;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.psychic {
color: #fff;
background-color: #f85888; }
.TypeIndicator__pokemonType__3MOQI.psychic::after {
box-shadow: 0 -4px #f85888, 0 -8px, 4px 0 #f85888, 4px -4px, 8px 0, 0 4px #f85888, 0 8px, -4px 0 #f85888, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.psychic.outline {
color: #f85888;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.ice {
color: #fff;
background-color: #98d8d8; }
.TypeIndicator__pokemonType__3MOQI.ice::after {
box-shadow: 0 -4px #98d8d8, 0 -8px, 4px 0 #98d8d8, 4px -4px, 8px 0, 0 4px #98d8d8, 0 8px, -4px 0 #98d8d8, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.ice.outline {
color: #98d8d8;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.dragon {
color: #fff;
background-color: #6f35fc; }
.TypeIndicator__pokemonType__3MOQI.dragon::after {
box-shadow: 0 -4px #6f35fc, 0 -8px, 4px 0 #6f35fc, 4px -4px, 8px 0, 0 4px #6f35fc, 0 8px, -4px 0 #6f35fc, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.dragon.outline {
color: #6f35fc;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.dark {
color: #fff;
background-color: #705848; }
.TypeIndicator__pokemonType__3MOQI.dark::after {
box-shadow: 0 -4px #705848, 0 -8px, 4px 0 #705848, 4px -4px, 8px 0, 0 4px #705848, 0 8px, -4px 0 #705848, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.dark.outline {
color: #705848;
background-color: #fff; }
.TypeIndicator__pokemonType__3MOQI.fairy {
color: #fff;
background-color: #ee99ac; }
.TypeIndicator__pokemonType__3MOQI.fairy::after {
box-shadow: 0 -4px #ee99ac, 0 -8px, 4px 0 #ee99ac, 4px -4px, 8px 0, 0 4px #ee99ac, 0 8px, -4px 0 #ee99ac, -4px 4px, -8px 0, -4px -4px, 4px 4px; }
.TypeIndicator__pokemonType__3MOQI.fairy.outline {
color: #ee99ac;
background-color: #fff; }
.MovesExplorer__wrapper__2y-BK {
font-size: 1em; }
@ -396,51 +450,50 @@
.MovesDropdown__legacy__3-s2n { }
.TypeEffectiveDisplay__multiplierWrapper__14os7 {
.TypeEffectiveDisplay__typeWrapper__3w4wT,
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi {
position: relative;
z-index: 0;
z-index: 0; }
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi {
padding-top: 6px;
padding-right: 6px; }
.TypeEffectiveDisplay__multiplierWrapper__14os7 > * {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi > * {
position: absolute; }
.TypeEffectiveDisplay__multiplierWrapper__14os7 :nth-child(1) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi :nth-child(1) {
position: inherit;
z-index: 3; }
.TypeEffectiveDisplay__multiplierWrapper__14os7 :nth-child(2) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi :nth-child(2) {
top: 0;
left: 6px;
z-index: 2; }
.TypeEffectiveDisplay__multiplierWrapper__14os7 :nth-child(3) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi :nth-child(3) {
left: 12px;
z-index: 1; }
.TypeEffectiveDisplay__multiplierWrapper__14os7 :nth-child(4) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi :nth-child(4) {
left: 18px;
z-index: 0; }
.TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX3__1SBG1 {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX3__35-RS {
padding-top: 12px;
padding-right: 12px; }
.TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX3__1SBG1 :nth-child(3) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX3__35-RS :nth-child(3) {
top: 0; }
.TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX3__1SBG1 :nth-child(2) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX3__35-RS :nth-child(2) {
top: 6px; }
.TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX4__2KqYa {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX4__2Onf7 {
padding-top: 18px;
padding-right: 18px; }
.TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX4__2KqYa :nth-child(4) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX4__2Onf7 :nth-child(4) {
top: 0; }
.TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX4__2KqYa :nth-child(3) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX4__2Onf7 :nth-child(3) {
top: 6px; }
.TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX4__2KqYa :nth-child(2) {
.TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX4__2Onf7 :nth-child(2) {
top: 12px; }
.TypeEffectiveDisplay__wrapper__1FFIj {
margin: 0 1em; }
.TypeEffectiveDisplay__wrapper__1FFIj * + h4 {
margin-top: 1em; }
.TypeEffectiveDisplay__wrapper__1FFIj h4 p {
font-size: 0.7em;
color: #b6b6b6;
margin: 0; }
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY {
display: flex;
flex-flow: row wrap;
@ -448,18 +501,31 @@
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY > * {
margin-right: 14px;
height: 0%; }
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__multiplierWrapper__14os7 {
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi {
width: auto;
margin-right: 2px; }
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX3__1SBG1 {
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX3__35-RS {
margin-right: -4px; }
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__multiplierWrapper__14os7.TypeEffectiveDisplay__multiplierWrapperX4__2KqYa {
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi.TypeEffectiveDisplay__typeMultiplierWrapperX4__2Onf7 {
margin-right: -10px; }
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY > *,
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__multiplierWrapper__14os7 > * {
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__typeWrapper__3w4wT > *,
.TypeEffectiveDisplay__wrapper__1FFIj .TypeEffectiveDisplay__indicatorWrapper__2F3AY .TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi > * {
flex-basis: unset;
width: 6.75rem; }
.TypeEffectiveDisplay__isCovered__3qyUq {
position: relative; }
.TypeEffectiveDisplay__isCovered__3qyUq::before {
content: "";
position: absolute;
right: 25px;
bottom: 20px;
z-index: 10;
width: 2px;
height: 2px;
color: #92cc41;
box-shadow: 18px 2px, 20px 2px, 16px 4px, 18px 4px, 20px 4px, 2px 6px, 14px 6px, 16px 6px, 2px 8px, 4px 8px, 12px 8px, 14px 8px, 4px 10px, 6px 10px, 10px 10px, 12px 10px, 6px 12px, 8px 12px, 10px 12px, 8px 14px; }
.MovesExplorer__wrapper__2y-BK {
font-size: 1em; }
.MovesExplorer__wrapper__2y-BK .title {

304
dist/main-bundle.js vendored
View File

@ -29619,7 +29619,7 @@ function pathToRegexp (path, keys, options) {
/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js because of ./node_modules/react-redux/es/index.js */
/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/@babel/runtime/helpers/esm/extends.js because of ./node_modules/react-redux/es/index.js */
/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/@babel/runtime/helpers/esm/inheritsLoose.js because of ./node_modules/react-redux/es/index.js */
/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js because of ./node_modules/react-measure/dist/index.esm.js */
/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/@babel/runtime/helpers/esm/objectWithoutPropertiesLoose.js because of ./node_modules/react-redux/es/index.js */
/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/react/index.js (<- Module is not an ECMAScript module) */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
@ -38391,7 +38391,8 @@ function (_react_1$default$Comp) {
onClick: onClick
}, react_1.default.createElement("span", null, moveStats.name), react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
className: typeCss,
type: moveStats.type
type: moveStats.type,
theme: TypeIndicator_1.TypeTheme.SOLID
})));
}
}], [{
@ -38472,14 +38473,14 @@ var react_1 = __importDefault(__webpack_require__(/*! react */ "./node_modules/r
var classnames_1 = __importDefault(__webpack_require__(/*! classnames */ "./node_modules/classnames/index.js"));
var Pokemon_1 = __webpack_require__(/*! app/models/Pokemon */ "./src/ts/app/models/Pokemon.ts");
var MovesDropdown_1 = __webpack_require__(/*! app/components/PokemonExplorer/MovesDropdown */ "./src/ts/app/components/PokemonExplorer/MovesDropdown.tsx");
var TypeEffectiveDisplay_1 = __webpack_require__(/*! ./TypeEffectiveDisplay */ "./src/ts/app/components/PokemonExplorer/TypeEffectiveDisplay.tsx");
var TypeIndicator_1 = __webpack_require__(/*! ./TypeIndicator */ "./src/ts/app/components/PokemonExplorer/TypeIndicator.tsx");
var types_1 = __webpack_require__(/*! app/utils/types */ "./src/ts/app/utils/types.ts");
var styles = __importStar(__webpack_require__(/*! app/components/PokemonExplorer/styles/MovesExplorer.scss */ "./src/ts/app/components/PokemonExplorer/styles/MovesExplorer.scss"));
var MovesExplorer =
@ -38497,40 +38498,9 @@ function (_react_1$default$Comp) {
_this.calculateTypeCoverage = function () {
var _this$props = _this.props,
selectedMoves = _this$props.selectedMoves,
movesById = _this$props.movesById,
attackTypeEffectiveness = _this$props.attackTypeEffectiveness;
var calculatedffectiveness = new Map();
Object.values(selectedMoves).forEach(function (move) {
var moveType = _this.getMoveType(move);
if (moveType !== null) {
var moveEffectiveness = attackTypeEffectiveness.get(moveType);
if (typeof moveEffectiveness !== 'undefined') {
moveEffectiveness.forEach(function (effectiveness, type) {
var currentEffectiveness = calculatedffectiveness.get(type);
if (typeof currentEffectiveness === 'undefined' || Pokemon_1.TypeEffectiveness[effectiveness] > Pokemon_1.TypeEffectiveness[currentEffectiveness]) {
calculatedffectiveness.set(type, effectiveness);
}
});
}
}
});
return calculatedffectiveness;
};
_this.getMoveType = function (move) {
var moveStats = null;
if (move !== null) {
moveStats = _this.props.movesById.get(move.id) || null;
}
if (moveStats !== null) {
return moveStats.type;
}
return null;
return types_1.calculateTypeCoverage(selectedMoves, movesById, attackTypeEffectiveness);
};
_this.handleToggleQuickMoveMenu = function (isOpen) {
@ -38573,17 +38543,18 @@ function (_react_1$default$Comp) {
movesById = _this$props2.movesById,
quickMoves = _this$props2.quickMoves,
chargeMoves = _this$props2.chargeMoves,
combatMoveSelectorsOpen = _this$props2.combatMoveSelectorsOpen;
combatMoveSelectorsOpen = _this$props2.combatMoveSelectorsOpen,
pokemonTypeWeaknesses = _this$props2.pokemonTypeWeaknesses;
var _this$props$selectedM = this.props.selectedMoves,
quickMove = _this$props$selectedM.quickMove,
chargeMove1 = _this$props$selectedM.chargeMove1,
chargeMove2 = _this$props$selectedM.chargeMove2;
var wrapperCss = classnames_1.default('nes-container', styles.wrapper);
var quickMoveType = this.getMoveType(quickMove);
var quickMoveType = types_1.getMoveType(quickMove, movesById);
var quickMoveCss = classnames_1.default(_defineProperty({}, styles.legacy, quickMove ? quickMove.isLegacy : false));
var chargeMove1Type = this.getMoveType(chargeMove1);
var chargeMove1Type = types_1.getMoveType(chargeMove1, movesById);
var chargeMove1Css = classnames_1.default(_defineProperty({}, styles.legacy, chargeMove1 ? chargeMove1.isLegacy : false));
var chargeMove2Type = this.getMoveType(chargeMove2);
var chargeMove2Type = types_1.getMoveType(chargeMove2, movesById);
var chargeMove2Css = classnames_1.default(_defineProperty({}, styles.legacy, chargeMove2 ? chargeMove2.isLegacy : false));
return react_1.default.createElement("div", {
className: wrapperCss
@ -38597,7 +38568,8 @@ function (_react_1$default$Comp) {
handleChangeSelectedOption: this.handleChangeQuickMove
}), quickMove && quickMoveType && react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
className: quickMoveCss,
type: quickMoveType
type: quickMoveType,
theme: TypeIndicator_1.TypeTheme.SOLID
}), react_1.default.createElement(MovesDropdown_1.MovesDropdown, {
isMenuOpen: combatMoveSelectorsOpen.chargeMove1,
menuLabel: "Charge Move 1",
@ -38608,7 +38580,8 @@ function (_react_1$default$Comp) {
handleChangeSelectedOption: this.handleChangeChargeMove1
}), chargeMove1 && chargeMove1Type && react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
className: chargeMove1Css,
type: chargeMove1Type
type: chargeMove1Type,
theme: TypeIndicator_1.TypeTheme.SOLID
}), react_1.default.createElement(MovesDropdown_1.MovesDropdown, {
isMenuOpen: combatMoveSelectorsOpen.chargeMove2,
menuLabel: "Charge Move 2",
@ -38619,10 +38592,12 @@ function (_react_1$default$Comp) {
handleChangeSelectedOption: this.handleChangeChargeMove2
}), chargeMove2 && chargeMove2Type && react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
className: chargeMove2Css,
type: chargeMove2Type
type: chargeMove2Type,
theme: TypeIndicator_1.TypeTheme.SOLID
}), react_1.default.createElement("div", null, react_1.default.createElement("h4", null, "Type Coverage"), react_1.default.createElement(TypeEffectiveDisplay_1.TypeEffectiveDisplay, {
pokemonName: "test",
effectiveness: this.calculateTypeCoverage()
mode: TypeEffectiveDisplay_1.EffectivenessMode.OFFENSE,
effectiveness: this.calculateTypeCoverage(),
coverage: pokemonTypeWeaknesses
})));
}
}]);
@ -38764,13 +38739,15 @@ function (_react_1$default$Comp) {
fairy: formatter_1.Forms.fairy.indexOf(leaguePokemon.form) > -1
});
var type1 = react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
type: leaguePokemon.types.type1
type: leaguePokemon.types.type1,
theme: TypeIndicator_1.TypeTheme.SOLID
});
var type2 = null;
if (leaguePokemon.types.type2) {
type2 = react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
type: leaguePokemon.types.type2
type: leaguePokemon.types.type2,
theme: TypeIndicator_1.TypeTheme.SOLID
});
}
@ -38874,6 +38851,8 @@ var react_redux_1 = __webpack_require__(/*! react-redux */ "./node_modules/react
var classnames_1 = __importDefault(__webpack_require__(/*! classnames */ "./node_modules/classnames/index.js"));
var Pokemon_1 = __webpack_require__(/*! app/models/Pokemon */ "./src/ts/app/models/Pokemon.ts");
var ActionsPokemonExplorer = __importStar(__webpack_require__(/*! app/components/PokemonExplorer/actions */ "./src/ts/app/components/PokemonExplorer/actions.ts"));
var LeagueIvExplorer_1 = __webpack_require__(/*! app/components/PokemonExplorer/LeagueIvExplorer */ "./src/ts/app/components/PokemonExplorer/LeagueIvExplorer.tsx");
@ -38886,6 +38865,8 @@ var TypeEffectiveDisplay_1 = __webpack_require__(/*! app/components/PokemonExplo
var navigation_1 = __webpack_require__(/*! app/utils/navigation */ "./src/ts/app/utils/navigation.ts");
var types_1 = __webpack_require__(/*! app/utils/types */ "./src/ts/app/utils/types.ts");
var styles = __importStar(__webpack_require__(/*! app/styles/PokemonApp.scss */ "./src/ts/app/styles/PokemonApp.scss"));
var PokemonExplorer =
@ -38900,6 +38881,18 @@ function (_react_1$default$Comp) {
_this = _possibleConstructorReturn(this, _getPrototypeOf(PokemonExplorer).call(this, props));
_this.getSuperEffectiveTypes = function (effectiveness) {
var superEffectiveTypes = [];
Array.from(effectiveness).reduce(function (accumulator, currentValue) {
if (currentValue[1] > Pokemon_1.TypeEffectiveness.NEUTRAL) {
accumulator.push(currentValue[0]);
}
return accumulator;
}, superEffectiveTypes);
return superEffectiveTypes;
};
_this.handleToggleDropdownOpen = function (menu, isOpen) {
var combatMoveSelectorsOpen = Object.assign({}, _this.props.pokemonExplorerState.combatMoveSelectorsOpen, _defineProperty({}, menu, isOpen));
@ -39037,7 +39030,11 @@ function (_react_1$default$Comp) {
var tmCss = classnames_1.default(iconCss, 'tm', {
active: widgets.moves
});
var tmButtonCss = classnames_1.default();
var tmButtonCss = classnames_1.default(); // weaknesses are indicated by types that cause super effective damage on defense
var pokemonTypeWeaknesses = leaguePokemon !== null ? this.getSuperEffectiveTypes(leaguePokemon.effectiveness) : []; // strengths are indicuated by types that do super effective damage on offense
var moveTypeStrengths = this.getSuperEffectiveTypes(types_1.calculateTypeCoverage(selectedCombatMoves, combatMoves, attackTypeEffectiveness));
return react_1.default.createElement("div", {
className: styles.body
}, react_1.default.createElement("div", {
@ -39045,10 +39042,13 @@ function (_react_1$default$Comp) {
}, leaguePokemon !== null && react_1.default.createElement(PokemonDisplay_1.PokemonDisplay, {
leaguePokemon: leaguePokemon,
isHighlighted: isOverlayShown
}), widgets.types && leaguePokemon !== null && react_1.default.createElement(TypeEffectiveDisplay_1.TypeEffectiveDisplay, {
}), widgets.types && leaguePokemon !== null && react_1.default.createElement("div", {
className: "nes-container"
}, react_1.default.createElement(TypeEffectiveDisplay_1.TypeEffectiveDisplay, {
mode: TypeEffectiveDisplay_1.EffectivenessMode.DEFENSE,
effectiveness: leaguePokemon.effectiveness,
pokemonName: leaguePokemon.name
}), widgets.pvp && leaguePokemon !== null && react_1.default.createElement(LeagueIvExplorer_1.LeagueIvExplorer, {
coverage: moveTypeStrengths
})), widgets.pvp && leaguePokemon !== null && react_1.default.createElement(LeagueIvExplorer_1.LeagueIvExplorer, {
activeLeague: league,
leaguePokemon: leaguePokemon,
individualValues: individualValues,
@ -39060,6 +39060,7 @@ function (_react_1$default$Comp) {
quickMoves: leaguePokemon.moves.quick,
chargeMoves: leaguePokemon.moves.cinematic,
selectedMoves: selectedCombatMoves,
pokemonTypeWeaknesses: pokemonTypeWeaknesses,
attackTypeEffectiveness: attackTypeEffectiveness,
combatMoveSelectorsOpen: combatMoveSelectorsOpen,
handleToggleDropdownOpen: this.handleToggleDropdownOpen,
@ -39281,72 +39282,125 @@ var TypeIndicator_1 = __webpack_require__(/*! ./TypeIndicator */ "./src/ts/app/c
var styles = __importStar(__webpack_require__(/*! app/components/PokemonExplorer/styles/TypeEffectiveDisplay.scss */ "./src/ts/app/components/PokemonExplorer/styles/TypeEffectiveDisplay.scss"));
var EffectivenessMode;
(function (EffectivenessMode) {
EffectivenessMode[EffectivenessMode["OFFENSE"] = 0] = "OFFENSE";
EffectivenessMode[EffectivenessMode["DEFENSE"] = 1] = "DEFENSE";
})(EffectivenessMode = exports.EffectivenessMode || (exports.EffectivenessMode = {}));
var TypeEffectiveDisplay =
/*#__PURE__*/
function (_react_1$default$Comp) {
_inherits(TypeEffectiveDisplay, _react_1$default$Comp);
function TypeEffectiveDisplay() {
var _this;
_classCallCheck(this, TypeEffectiveDisplay);
return _possibleConstructorReturn(this, _getPrototypeOf(TypeEffectiveDisplay).apply(this, arguments));
_this = _possibleConstructorReturn(this, _getPrototypeOf(TypeEffectiveDisplay).apply(this, arguments));
_this.isTypeCovered = function (type) {
return _this.props.coverage.some(function (coverageType) {
return coverageType === type;
});
};
return _this;
}
_createClass(TypeEffectiveDisplay, [{
key: "render",
value: function render() {
var _this2 = this;
var _this$props = this.props,
effectiveness = _this$props.effectiveness,
pokemonName = _this$props.pokemonName;
mode = _this$props.mode,
effectiveness = _this$props.effectiveness;
var wrapperCss = classnames_1.default('nes-container', styles.wrapper);
var indicatorWrapperCss = classnames_1.default(styles.indicatorWrapper);
var multiplierWrapperX2Css = classnames_1.default(styles.multiplierWrapper);
var multiplierWrapperX3Css = classnames_1.default(styles.multiplierWrapper, styles.multiplierWrapperX3);
var multiplierWrapperX4Css = classnames_1.default(styles.multiplierWrapper, styles.multiplierWrapperX4);
var multiplierWrapperX2Css = classnames_1.default(styles.typeMultiplierWrapper);
var multiplierWrapperX3Css = classnames_1.default(styles.typeMultiplierWrapper, styles.typeMultiplierWrapperX3);
var multiplierWrapperX4Css = classnames_1.default(styles.typeMultiplierWrapper, styles.typeMultiplierWrapperX4);
var superEffectiveX2 = [];
var superEffective = [];
var notVeryEffective = [];
var notVeryEffectiveX2 = [];
var notVeryEffectiveX3 = [];
var notVeryEffectiveX4 = [];
var supereffectiveCoverage = [];
var supereffectiveCoverageX2 = [];
var notVeryEffectiveCoverage = [];
var notVeryEffectiveCoverageX2 = [];
var notVeryEffectiveCoverageX3 = [];
var notVeryEffectiveCoverageX4 = [];
effectiveness.forEach(function (value, key) {
var typeIndicator;
if (value === Pokemon_1.TypeEffectiveness.SUPER_EFFECTIVE || value === Pokemon_1.TypeEffectiveness.NOT_VERY_EFFECTIVE) {
// using `key` because these are later transformed into an array of duplicate elements
typeIndicator = react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
key: key,
type: key
});
} else {
typeIndicator = react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
type: key
});
}
switch (value) {
case Pokemon_1.TypeEffectiveness.SUPER_EFFECTIVE_X2:
superEffectiveX2.push(typeIndicator);
superEffectiveX2.push(react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
type: key,
theme: TypeIndicator_1.TypeTheme.SOLID
}));
supereffectiveCoverageX2.push(_this2.isTypeCovered(key));
break;
case Pokemon_1.TypeEffectiveness.SUPER_EFFECTIVE:
superEffective.push(typeIndicator);
superEffective.push(react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
key: key,
type: key,
theme: TypeIndicator_1.TypeTheme.SOLID
}));
supereffectiveCoverage.push(_this2.isTypeCovered(key));
break;
case Pokemon_1.TypeEffectiveness.NOT_VERY_EFFECTIVE:
notVeryEffective.push(typeIndicator);
notVeryEffective.push(react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
key: key,
type: key,
theme: TypeIndicator_1.TypeTheme.OUTLINE
}));
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverage.push(_this2.isTypeCovered(key));
}
break;
case Pokemon_1.TypeEffectiveness.IMMUNE:
notVeryEffectiveX2.push(typeIndicator);
notVeryEffectiveX2.push(react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
type: key,
theme: TypeIndicator_1.TypeTheme.OUTLINE
}));
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverageX2.push(_this2.isTypeCovered(key));
}
break;
case Pokemon_1.TypeEffectiveness.NOT_VERY_EFFECTIVE_X3:
notVeryEffectiveX3.push(typeIndicator);
notVeryEffectiveX3.push(react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
type: key,
theme: TypeIndicator_1.TypeTheme.OUTLINE
}));
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverageX3.push(_this2.isTypeCovered(key));
}
break;
case Pokemon_1.TypeEffectiveness.IMMUNE_X2:
notVeryEffectiveX4.push(typeIndicator);
notVeryEffectiveX4.push(react_1.default.createElement(TypeIndicator_1.TypeIndicator, {
type: key,
theme: TypeIndicator_1.TypeTheme.OUTLINE
}));
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverageX4.push(_this2.isTypeCovered(key));
}
break;
case Pokemon_1.TypeEffectiveness.NEUTRAL:
@ -39360,31 +39414,41 @@ function (_react_1$default$Comp) {
});
return react_1.default.createElement("div", {
className: wrapperCss
}, (notVeryEffective.length > 0 || notVeryEffectiveX2.length > 0 || notVeryEffectiveX3.length > 0 || notVeryEffectiveX4.length > 0) && react_1.default.createElement(react_1.default.Fragment, null, react_1.default.createElement("h4", null, pokemonName, "'s Resistances", react_1.default.createElement("p", null, "It's Not Very Effective...")), react_1.default.createElement("div", {
}, (notVeryEffective.length > 0 || notVeryEffectiveX2.length > 0 || notVeryEffectiveX3.length > 0 || notVeryEffectiveX4.length > 0) && react_1.default.createElement(react_1.default.Fragment, null, react_1.default.createElement("h4", null, mode === EffectivenessMode.DEFENSE ? 'Resistances' : "It's not very effective..."), react_1.default.createElement("div", {
className: indicatorWrapperCss
}, notVeryEffectiveX4.length > 0 && notVeryEffectiveX4.map(function (element, index) {
return react_1.default.createElement("div", {
key: "-4x".concat(index),
className: multiplierWrapperX4Css
className: "".concat(multiplierWrapperX4Css, " ").concat(notVeryEffectiveCoverageX4[index] ? styles.isCovered : '')
}, element, element, element, element);
}), notVeryEffectiveX3.length > 0 && notVeryEffectiveX3.map(function (element, index) {
return react_1.default.createElement("div", {
key: "-3x".concat(index),
className: multiplierWrapperX3Css
className: "".concat(multiplierWrapperX3Css, " ").concat(notVeryEffectiveCoverageX2[index] ? styles.isCovered : '')
}, element, element, element);
}), notVeryEffectiveX2.length > 0 && notVeryEffectiveX2.map(function (element, index) {
return react_1.default.createElement("div", {
key: "-2x".concat(index),
className: multiplierWrapperX2Css
className: "".concat(multiplierWrapperX2Css, " ").concat(notVeryEffectiveCoverageX2[index] ? styles.isCovered : '')
}, element, element);
}), notVeryEffective.length > 0 && notVeryEffective)), (superEffective.length > 0 || superEffectiveX2.length > 0) && react_1.default.createElement(react_1.default.Fragment, null, react_1.default.createElement("h4", null, pokemonName, "'s Weaknesses", react_1.default.createElement("p", null, "It's Super Effective!")), react_1.default.createElement("div", {
}), notVeryEffective.length > 0 && notVeryEffective.map(function (element, index) {
return react_1.default.createElement("div", {
key: index,
className: "".concat(styles.typeWrapper, " ").concat(notVeryEffectiveCoverage[index] ? styles.isCovered : '')
}, element);
}))), (superEffective.length > 0 || superEffectiveX2.length > 0) && react_1.default.createElement(react_1.default.Fragment, null, react_1.default.createElement("h4", null, mode === EffectivenessMode.DEFENSE ? 'Weaknesses' : "It's super effective!"), react_1.default.createElement("div", {
className: indicatorWrapperCss
}, superEffectiveX2.length > 0 && superEffectiveX2.map(function (element, index) {
return react_1.default.createElement("div", {
key: "+2x".concat(index),
className: multiplierWrapperX2Css
className: "".concat(multiplierWrapperX2Css, " ").concat(supereffectiveCoverageX2[index] ? styles.isCovered : '')
}, element, element);
}), superEffective.length > 0 && superEffective)));
}), superEffective.length > 0 && superEffective.map(function (element, index) {
return react_1.default.createElement("div", {
key: index,
className: "".concat(styles.typeWrapper, " ").concat(supereffectiveCoverage[index] ? styles.isCovered : '')
}, element);
}))));
}
}]);
@ -39452,6 +39516,13 @@ var formatter_1 = __webpack_require__(/*! app/utils/formatter */ "./src/ts/app/u
var styles = __importStar(__webpack_require__(/*! app/components/PokemonExplorer/styles/TypeIndicator.scss */ "./src/ts/app/components/PokemonExplorer/styles/TypeIndicator.scss"));
var TypeTheme;
(function (TypeTheme) {
TypeTheme[TypeTheme["SOLID"] = 0] = "SOLID";
TypeTheme[TypeTheme["OUTLINE"] = 1] = "OUTLINE";
})(TypeTheme = exports.TypeTheme || (exports.TypeTheme = {}));
var TypeIndicator =
/*#__PURE__*/
function (_react_1$default$Comp) {
@ -39468,10 +39539,12 @@ function (_react_1$default$Comp) {
value: function render() {
var _this$props = this.props,
className = _this$props.className,
theme = _this$props.theme,
type = _this$props.type;
var containerCss = classnames_1.default('nes-container', 'with-title');
var containerRoundCss = classnames_1.default(containerCss, 'is-rounded');
var pokemonTypeCss = classnames_1.default(className, containerRoundCss, styles.pokemonType);
var containerCss = classnames_1.default('nes-container', 'with-title', 'is-rounded');
var pokemonTypeCss = classnames_1.default(className, containerCss, styles.pokemonType, {
outline: theme === TypeTheme.OUTLINE
});
return react_1.default.createElement("div", {
className: "".concat(pokemonTypeCss, " ").concat(formatter_1.formatType(type))
}, formatter_1.formatType(type));
@ -39890,7 +39963,7 @@ module.exports = {"baseStatRow":"StatDisplay__baseStatRow__1B60A"};
/***/ (function(module, exports, __webpack_require__) {
// extracted by mini-css-extract-plugin
module.exports = {"multiplierWrapper":"TypeEffectiveDisplay__multiplierWrapper__14os7","multiplierWrapperX3":"TypeEffectiveDisplay__multiplierWrapperX3__1SBG1","multiplierWrapperX4":"TypeEffectiveDisplay__multiplierWrapperX4__2KqYa","wrapper":"TypeEffectiveDisplay__wrapper__1FFIj","indicatorWrapper":"TypeEffectiveDisplay__indicatorWrapper__2F3AY"};
module.exports = {"typeWrapper":"TypeEffectiveDisplay__typeWrapper__3w4wT","typeMultiplierWrapper":"TypeEffectiveDisplay__typeMultiplierWrapper__1WOCi","typeMultiplierWrapperX3":"TypeEffectiveDisplay__typeMultiplierWrapperX3__35-RS","typeMultiplierWrapperX4":"TypeEffectiveDisplay__typeMultiplierWrapperX4__2Onf7","wrapper":"TypeEffectiveDisplay__wrapper__1FFIj","indicatorWrapper":"TypeEffectiveDisplay__indicatorWrapper__2F3AY","isCovered":"TypeEffectiveDisplay__isCovered__3qyUq"};
/***/ }),
@ -41180,6 +41253,59 @@ exports.appendQueryString = function (location, parameters) {
return '?' + search.toString();
};
/***/ }),
/***/ "./src/ts/app/utils/types.ts":
/*!***********************************!*\
!*** ./src/ts/app/utils/types.ts ***!
\***********************************/
/*! no static exports found */
/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
/***/ (function(module, exports, __webpack_require__) {
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.calculateTypeCoverage = function (selectedMoves, movesById, attackTypeEffectiveness) {
var calculatedffectiveness = new Map();
Object.values(selectedMoves).forEach(function (move) {
var moveType = exports.getMoveType(move, movesById);
if (moveType !== null) {
var moveEffectiveness = attackTypeEffectiveness.get(moveType);
if (typeof moveEffectiveness !== 'undefined') {
moveEffectiveness.forEach(function (effectiveness, type) {
var currentEffectiveness = calculatedffectiveness.get(type);
if (typeof currentEffectiveness === 'undefined' || effectiveness > currentEffectiveness) {
calculatedffectiveness.set(type, effectiveness);
}
});
}
}
});
return calculatedffectiveness;
};
exports.getMoveType = function (move, movesById) {
var moveStats = null;
if (move !== null) {
moveStats = movesById.get(move.id) || null;
}
if (moveStats !== null) {
return moveStats.type;
}
return null;
};
/***/ })
/******/ });

View File

@ -1,4 +1,5 @@
@import '~nes.css/scss/base/color-palette';
@import '~nes.css/scss/base/variables';
$container-width: (
desktop: 425px,
@ -51,6 +52,7 @@ $main-active-font-color: $gray-scale-1;
$main-border-color: $gray-scale-4;
$main-overlay-color: $gray-scale-4;
$main-hover-color: darken($main-background-color, 5%);
$main-success: map-get($success-colors, 'normal');
$great-league-colors: (
primary: #649bde,

View File

@ -6,7 +6,7 @@ import classNames from 'classnames';
import { CombatMoveStats, IPokemonMove } from 'app/models/Pokemon';
import { TypeIndicator } from './TypeIndicator';
import { TypeIndicator, TypeTheme } from './TypeIndicator';
import * as styles from 'app/components/PokemonExplorer/styles/MovesDropdown.scss';
@ -174,7 +174,7 @@ export class MovesDropdown extends React.Component<IMovesDropdownProps, IState>
onClick={ onClick }
>
<span>{ moveStats.name }</span>
<TypeIndicator className={ typeCss } type={ moveStats.type } />
<TypeIndicator className={ typeCss } type={ moveStats.type } theme={ TypeTheme.SOLID }/>
</a>
}
</React.Fragment>

View File

@ -5,13 +5,15 @@ import React from 'react';
import classNames from 'classnames';
import { AttackTypeEffectiveness } from 'app/models/Config';
import { CombatMoveStats, ICombatMoveStats, IPokemonMove, TypeEffectiveness } from 'app/models/Pokemon';
import { CombatMoveStats, IPokemon, IPokemonMove } from 'app/models/Pokemon';
import { CombatMoveSelectorsOpen, SelectedCombatMoves } from 'app/components/PokemonExplorer/types';
import { MovesDropdown } from 'app/components/PokemonExplorer/MovesDropdown';
import { TypeEffectiveDisplay } from './TypeEffectiveDisplay';
import { TypeIndicator } from './TypeIndicator';
import { EffectivenessMode, TypeEffectiveDisplay } from './TypeEffectiveDisplay';
import { TypeIndicator, TypeTheme } from './TypeIndicator';
import { calculateTypeCoverage, getMoveType } from 'app/utils/types';
import * as styles from 'app/components/PokemonExplorer/styles/MovesExplorer.scss';
@ -20,6 +22,7 @@ export interface IMovesExplorerProps {
quickMoves : Array<IPokemonMove>;
chargeMoves : Array<IPokemonMove>;
selectedMoves : SelectedCombatMoves;
pokemonTypeWeaknesses : Array<POGOProtos.Enums.PokemonType>;
attackTypeEffectiveness : AttackTypeEffectiveness;
combatMoveSelectorsOpen : CombatMoveSelectorsOpen;
handleToggleDropdownOpen : (menu : keyof CombatMoveSelectorsOpen, isOpen : boolean) => void;
@ -34,6 +37,7 @@ export class MovesExplorer extends React.Component<IMovesExplorerProps> {
quickMoves,
chargeMoves,
combatMoveSelectorsOpen,
pokemonTypeWeaknesses,
} = this.props;
const {
quickMove,
@ -46,15 +50,15 @@ export class MovesExplorer extends React.Component<IMovesExplorerProps> {
styles.wrapper,
);
const quickMoveType = this.getMoveType(quickMove);
const quickMoveType = getMoveType(quickMove, movesById);
const quickMoveCss = classNames({
[styles.legacy]: quickMove ? quickMove.isLegacy : false,
});
const chargeMove1Type = this.getMoveType(chargeMove1);
const chargeMove1Type = getMoveType(chargeMove1, movesById);
const chargeMove1Css = classNames({
[styles.legacy]: chargeMove1 ? chargeMove1.isLegacy : false,
});
const chargeMove2Type = this.getMoveType(chargeMove2);
const chargeMove2Type = getMoveType(chargeMove2, movesById);
const chargeMove2Css = classNames({
[styles.legacy]: chargeMove2 ? chargeMove2.isLegacy : false,
});
@ -71,7 +75,7 @@ export class MovesExplorer extends React.Component<IMovesExplorerProps> {
handleChangeSelectedOption={ this.handleChangeQuickMove }
/>
{ quickMove && quickMoveType &&
<TypeIndicator className={ quickMoveCss } type={ quickMoveType } />
<TypeIndicator className={ quickMoveCss } type={ quickMoveType } theme={ TypeTheme.SOLID }/>
}
<MovesDropdown
isMenuOpen={ combatMoveSelectorsOpen.chargeMove1 }
@ -83,7 +87,7 @@ export class MovesExplorer extends React.Component<IMovesExplorerProps> {
handleChangeSelectedOption={ this.handleChangeChargeMove1 }
/>
{ chargeMove1 && chargeMove1Type &&
<TypeIndicator className={ chargeMove1Css } type={ chargeMove1Type } />
<TypeIndicator className={ chargeMove1Css } type={ chargeMove1Type } theme={ TypeTheme.SOLID }/>
}
<MovesDropdown
isMenuOpen={ combatMoveSelectorsOpen.chargeMove2 }
@ -95,13 +99,14 @@ export class MovesExplorer extends React.Component<IMovesExplorerProps> {
handleChangeSelectedOption={ this.handleChangeChargeMove2 }
/>
{ chargeMove2 && chargeMove2Type &&
<TypeIndicator className={ chargeMove2Css } type={ chargeMove2Type } />
<TypeIndicator className={ chargeMove2Css } type={ chargeMove2Type } theme={ TypeTheme.SOLID }/>
}
<div>
<h4>Type Coverage</h4>
<TypeEffectiveDisplay
pokemonName="test"
mode={ EffectivenessMode.OFFENSE }
effectiveness={ this.calculateTypeCoverage() }
coverage={ pokemonTypeWeaknesses }
/>
</div>
</div>
@ -111,36 +116,10 @@ export class MovesExplorer extends React.Component<IMovesExplorerProps> {
private readonly calculateTypeCoverage = () => {
const {
selectedMoves,
movesById,
attackTypeEffectiveness,
} = this.props;
const calculatedffectiveness : Map<POGOProtos.Enums.PokemonType, TypeEffectiveness> = new Map();
Object.values(selectedMoves).forEach((move) => {
const moveType = this.getMoveType(move);
if (moveType !== null) {
const moveEffectiveness = attackTypeEffectiveness.get(moveType);
if (typeof moveEffectiveness !== 'undefined') {
moveEffectiveness.forEach((effectiveness, type) => {
const currentEffectiveness = calculatedffectiveness.get(type);
if (typeof currentEffectiveness === 'undefined' || TypeEffectiveness[effectiveness] > TypeEffectiveness[currentEffectiveness]) {
calculatedffectiveness.set(type, effectiveness);
}
});
}
}
});
return calculatedffectiveness;
}
private readonly getMoveType = (move : IPokemonMove | null) => {
let moveStats : ICombatMoveStats | null = null;
if (move !== null) {
moveStats = this.props.movesById.get(move.id) || null;
}
if (moveStats !== null) {
return moveStats.type;
}
return null;
return calculateTypeCoverage(selectedMoves, movesById, attackTypeEffectiveness);
}
private readonly handleToggleQuickMoveMenu = (isOpen : boolean) => {

View File

@ -9,7 +9,7 @@ import { IPokemon } from 'app/models/Pokemon';
import { formatDexNumber, formatForm, Forms } from 'app/utils/formatter';
import { StatDisplay } from './StatDisplay';
import { TypeIndicator } from './TypeIndicator';
import { TypeIndicator, TypeTheme } from './TypeIndicator';
import * as styles from 'app/components/PokemonExplorer/styles/PokemonDisplay.scss';
@ -95,10 +95,10 @@ export class PokemonDisplay extends React.Component<IPokemonDisplay> {
},
);
const type1 = <TypeIndicator type={ leaguePokemon.types.type1 } />;
const type1 = <TypeIndicator type={ leaguePokemon.types.type1 } theme={ TypeTheme.SOLID }/>;
let type2 : JSX.Element | null = null;
if (leaguePokemon.types.type2) {
type2 = <TypeIndicator type={ leaguePokemon.types.type2 } />;
type2 = <TypeIndicator type={ leaguePokemon.types.type2 } theme={ TypeTheme.SOLID }/>;
}
return (

View File

@ -1,3 +1,5 @@
import POGOProtos from 'pogo-protos';
import React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps } from 'react-router-dom';
@ -6,7 +8,7 @@ import classNames from 'classnames';
import { AttackTypeEffectiveness } from 'app/models/Config';
import { League } from 'app/models/League';
import { CombatMoveStats } from 'app/models/Pokemon';
import { CombatMoveStats, TypeEffectiveness } from 'app/models/Pokemon';
import * as ActionsPokemonExplorer from 'app/components/PokemonExplorer/actions';
import {
@ -21,9 +23,10 @@ import { IRouterProps } from 'app/types';
import { LeagueIvExplorer } from 'app/components/PokemonExplorer/LeagueIvExplorer';
import { MovesExplorer } from 'app/components/PokemonExplorer/MovesExplorer';
import { PokemonDisplay } from 'app/components/PokemonExplorer/PokemonDisplay';
import { TypeEffectiveDisplay } from 'app/components/PokemonExplorer/TypeEffectiveDisplay';
import { EffectivenessMode, TypeEffectiveDisplay } from 'app/components/PokemonExplorer/TypeEffectiveDisplay';
import { appendQueryString } from 'app/utils/navigation';
import { calculateTypeCoverage } from 'app/utils/types';
import * as styles from 'app/styles/PokemonApp.scss';
@ -125,6 +128,11 @@ class PokemonExplorer extends React.Component<IConnectedPokemonExplorerProps, IS
// }
);
// weaknesses are indicated by types that cause super effective damage on defense
const pokemonTypeWeaknesses = leaguePokemon !== null ? this.getSuperEffectiveTypes(leaguePokemon.effectiveness) : [];
// strengths are indicuated by types that do super effective damage on offense
const moveTypeStrengths = this.getSuperEffectiveTypes(calculateTypeCoverage(selectedCombatMoves, combatMoves, attackTypeEffectiveness));
return (
<div className={ styles.body }>
<div className={ displayWrapperCss }>
@ -135,10 +143,13 @@ class PokemonExplorer extends React.Component<IConnectedPokemonExplorerProps, IS
/>
}
{ widgets.types && leaguePokemon !== null &&
<div className="nes-container">
<TypeEffectiveDisplay
mode={ EffectivenessMode.DEFENSE }
effectiveness={ leaguePokemon.effectiveness }
pokemonName={ leaguePokemon.name }
coverage={ moveTypeStrengths }
/>
</div>
}
{ widgets.pvp && leaguePokemon !== null &&
<LeagueIvExplorer
@ -156,6 +167,7 @@ class PokemonExplorer extends React.Component<IConnectedPokemonExplorerProps, IS
quickMoves={ leaguePokemon.moves.quick }
chargeMoves={ leaguePokemon.moves.cinematic }
selectedMoves={ selectedCombatMoves }
pokemonTypeWeaknesses={ pokemonTypeWeaknesses }
attackTypeEffectiveness={ attackTypeEffectiveness }
combatMoveSelectorsOpen={ combatMoveSelectorsOpen }
handleToggleDropdownOpen={ this.handleToggleDropdownOpen }
@ -175,6 +187,17 @@ class PokemonExplorer extends React.Component<IConnectedPokemonExplorerProps, IS
);
}
private readonly getSuperEffectiveTypes = (effectiveness : Map<POGOProtos.Enums.PokemonType, TypeEffectiveness>) => {
const superEffectiveTypes : Array<POGOProtos.Enums.PokemonType> = [];
Array.from(effectiveness).reduce((accumulator, currentValue) => {
if (currentValue[1] > TypeEffectiveness.NEUTRAL) {
accumulator.push(currentValue[0]);
}
return accumulator;
}, superEffectiveTypes);
return superEffectiveTypes;
}
private readonly handleToggleDropdownOpen = (menu : keyof CombatMoveSelectorsOpen, isOpen : boolean) => {
const combatMoveSelectorsOpen : CombatMoveSelectorsOpen = {
...this.props.pokemonExplorerState.combatMoveSelectorsOpen,

View File

@ -1,24 +1,32 @@
import POGOProtos from 'pogo-protos';
import React from 'react';
import classNames from 'classnames';
import { IPokemon, TypeEffectiveness } from 'app/models/Pokemon';
import { TypeIndicator } from './TypeIndicator';
import { TypeIndicator, TypeTheme } from './TypeIndicator';
import * as styles from 'app/components/PokemonExplorer/styles/TypeEffectiveDisplay.scss';
export enum EffectivenessMode {
OFFENSE,
DEFENSE,
}
export interface ITypeEffectiveDisplayProps {
pokemonName : string;
mode : EffectivenessMode;
effectiveness : IPokemon['effectiveness'];
coverage : Array<POGOProtos.Enums.PokemonType>;
}
export class TypeEffectiveDisplay extends React.Component<ITypeEffectiveDisplayProps> {
public render() {
const {
mode,
effectiveness,
pokemonName,
} = this.props;
const wrapperCss = classNames(
@ -29,15 +37,15 @@ export class TypeEffectiveDisplay extends React.Component<ITypeEffectiveDisplayP
styles.indicatorWrapper,
);
const multiplierWrapperX2Css = classNames(
styles.multiplierWrapper,
styles.typeMultiplierWrapper,
);
const multiplierWrapperX3Css = classNames(
styles.multiplierWrapper,
styles.multiplierWrapperX3,
styles.typeMultiplierWrapper,
styles.typeMultiplierWrapperX3,
);
const multiplierWrapperX4Css = classNames(
styles.multiplierWrapper,
styles.multiplierWrapperX4,
styles.typeMultiplierWrapper,
styles.typeMultiplierWrapperX4,
);
const superEffectiveX2 : Array<JSX.Element> = [];
@ -46,35 +54,45 @@ export class TypeEffectiveDisplay extends React.Component<ITypeEffectiveDisplayP
const notVeryEffectiveX2 : Array<JSX.Element> = [];
const notVeryEffectiveX3 : Array<JSX.Element> = [];
const notVeryEffectiveX4 : Array<JSX.Element> = [];
const supereffectiveCoverage : Array<boolean> = [];
const supereffectiveCoverageX2 : Array<boolean> = [];
const notVeryEffectiveCoverage : Array<boolean> = [];
const notVeryEffectiveCoverageX2 : Array<boolean> = [];
const notVeryEffectiveCoverageX3 : Array<boolean> = [];
const notVeryEffectiveCoverageX4 : Array<boolean> = [];
effectiveness.forEach((value, key) => {
let typeIndicator : JSX.Element;
if (value === TypeEffectiveness.SUPER_EFFECTIVE ||
value === TypeEffectiveness.NOT_VERY_EFFECTIVE
) {
// using `key` because these are later transformed into an array of duplicate elements
typeIndicator = <TypeIndicator key={ key } type={ key } />;
} else {
typeIndicator = <TypeIndicator type={ key } />;
}
switch (value) {
case TypeEffectiveness.SUPER_EFFECTIVE_X2:
superEffectiveX2.push(typeIndicator);
superEffectiveX2.push(<TypeIndicator type={ key } theme={ TypeTheme.SOLID } />);
supereffectiveCoverageX2.push(this.isTypeCovered(key));
break;
case TypeEffectiveness.SUPER_EFFECTIVE:
superEffective.push(typeIndicator);
superEffective.push(<TypeIndicator key={ key } type={ key } theme={ TypeTheme.SOLID } />);
supereffectiveCoverage.push(this.isTypeCovered(key));
break;
case TypeEffectiveness.NOT_VERY_EFFECTIVE:
notVeryEffective.push(typeIndicator);
notVeryEffective.push(<TypeIndicator key={ key } type={ key } theme={ TypeTheme.OUTLINE } />);
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverage.push(this.isTypeCovered(key));
}
break;
case TypeEffectiveness.IMMUNE:
notVeryEffectiveX2.push(typeIndicator);
notVeryEffectiveX2.push(<TypeIndicator type={ key } theme={ TypeTheme.OUTLINE } />);
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverageX2.push(this.isTypeCovered(key));
}
break;
case TypeEffectiveness.NOT_VERY_EFFECTIVE_X3:
notVeryEffectiveX3.push(typeIndicator);
notVeryEffectiveX3.push(<TypeIndicator type={ key } theme={ TypeTheme.OUTLINE } />);
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverageX3.push(this.isTypeCovered(key));
}
break;
case TypeEffectiveness.IMMUNE_X2:
notVeryEffectiveX4.push(typeIndicator);
notVeryEffectiveX4.push(<TypeIndicator type={ key } theme={ TypeTheme.OUTLINE } />);
if (mode === EffectivenessMode.DEFENSE) {
notVeryEffectiveCoverageX4.push(this.isTypeCovered(key));
}
break;
case TypeEffectiveness.NEUTRAL:
// do nothing
@ -89,32 +107,56 @@ export class TypeEffectiveDisplay extends React.Component<ITypeEffectiveDisplayP
<div className={ wrapperCss }>
{ (notVeryEffective.length > 0 || notVeryEffectiveX2.length > 0 || notVeryEffectiveX3.length > 0 || notVeryEffectiveX4.length > 0) &&
<React.Fragment>
<h4>{ pokemonName }'s Resistances<p>It's Not Very Effective...</p></h4>
<h4>{ mode === EffectivenessMode.DEFENSE ? 'Resistances' : `It's not very effective...` }</h4>
<div className={ indicatorWrapperCss }>
{ notVeryEffectiveX4.length > 0 &&
notVeryEffectiveX4.map((element, index) => <div key={ `-4x${index}` } className={ multiplierWrapperX4Css }>{ element }{ element }{ element }{ element }</div>)
notVeryEffectiveX4.map((element, index) =>
<div key={ `-4x${index}` } className={ `${multiplierWrapperX4Css} ${notVeryEffectiveCoverageX4[index] ? styles.isCovered : ''}` }>
{ element }{ element }{ element }{ element }
</div>
)
}
{ notVeryEffectiveX3.length > 0 &&
notVeryEffectiveX3.map((element, index) => <div key={ `-3x${index}` } className={ multiplierWrapperX3Css }>{ element }{ element }{ element }</div>)
notVeryEffectiveX3.map((element, index) =>
<div key={ `-3x${index}` } className={ `${multiplierWrapperX3Css} ${notVeryEffectiveCoverageX2[index] ? styles.isCovered : ''}` }>
{ element }{ element }{ element }
</div>
)
}
{ notVeryEffectiveX2.length > 0 &&
notVeryEffectiveX2.map((element, index) => <div key={ `-2x${index}` } className={ multiplierWrapperX2Css }>{ element }{ element }</div>)
notVeryEffectiveX2.map((element, index) =>
<div key={ `-2x${index}` } className={ `${multiplierWrapperX2Css} ${notVeryEffectiveCoverageX2[index] ? styles.isCovered : ''}` }>
{ element }{ element }
</div>
)
}
{ notVeryEffective.length > 0 &&
notVeryEffective
notVeryEffective.map((element, index) =>
<div key={ index } className={ `${styles.typeWrapper} ${notVeryEffectiveCoverage[index] ? styles.isCovered : ''}` }>
{ element }
</div>
)
}
</div>
</React.Fragment>
}
{ (superEffective.length > 0 || superEffectiveX2.length > 0) &&
<React.Fragment>
<h4>{ pokemonName }'s Weaknesses<p>It's Super Effective!</p></h4>
<h4>{ mode === EffectivenessMode.DEFENSE ? 'Weaknesses' : `It's super effective!` }</h4>
<div className={ indicatorWrapperCss }>
{ superEffectiveX2.length > 0 &&
superEffectiveX2.map((element, index) => <div key={ `+2x${index}` } className={ multiplierWrapperX2Css }>{ element }{ element }</div>)
superEffectiveX2.map((element, index) =>
<div key={ `+2x${index}` } className={ `${multiplierWrapperX2Css} ${supereffectiveCoverageX2[index] ? styles.isCovered : ''}` }>
{ element }{ element }
</div>
)
}
{ superEffective.length > 0 &&
superEffective
superEffective.map((element, index) =>
<div key={ index } className={ `${styles.typeWrapper} ${supereffectiveCoverage[index] ? styles.isCovered : ''}` }>
{ element }
</div>
)
}
</div>
</React.Fragment>
@ -122,4 +164,10 @@ export class TypeEffectiveDisplay extends React.Component<ITypeEffectiveDisplayP
</div>
);
}
private readonly isTypeCovered = (type : POGOProtos.Enums.PokemonType) => {
return this.props.coverage.some((coverageType) => {
return coverageType === type;
});
}
}

View File

@ -8,27 +8,37 @@ import { formatType } from 'app/utils/formatter';
import * as styles from 'app/components/PokemonExplorer/styles/TypeIndicator.scss';
export enum TypeTheme {
SOLID,
OUTLINE,
}
export interface ITypeEffectiveDisplayProps {
className? : string;
type : POGOProtos.Enums.PokemonType;
theme : TypeTheme;
}
export class TypeIndicator extends React.Component<ITypeEffectiveDisplayProps> {
public render() {
const { className, type } = this.props;
const {
className,
theme,
type,
} = this.props;
const containerCss = classNames(
'nes-container',
'with-title',
);
const containerRoundCss = classNames(
containerCss,
'is-rounded',
);
const pokemonTypeCss = classNames(
className,
containerRoundCss,
containerCss,
styles.pokemonType,
{
outline: theme === TypeTheme.OUTLINE
}
);
return <div className={ `${pokemonTypeCss} ${formatType(type)}` }>{ formatType(type) }</div>;

View File

@ -1,8 +1,12 @@
@import '~styles/Variables.scss';
.multiplierWrapper {
.typeWrapper,
.typeMultiplierWrapper {
position: relative;
z-index: 0; // so the contents don't show up over the overlay
}
.typeMultiplierWrapper {
padding-top: 6px;
padding-right: 6px;
@ -31,7 +35,7 @@
z-index: 0;
}
&.multiplierWrapperX3 {
&.typeMultiplierWrapperX3 {
padding-top: 12px;
padding-right: 12px;
@ -44,7 +48,7 @@
}
}
&.multiplierWrapperX4 {
&.typeMultiplierWrapperX4 {
padding-top: 18px;
padding-right: 18px;
@ -69,12 +73,6 @@
margin-top: 1em;
}
h4 p {
font-size: 0.7em;
color: $main-font-secondary-color;
margin: 0;
}
.indicatorWrapper {
display: flex;
flex-flow: row wrap;
@ -85,23 +83,40 @@
height: 0%; // stop single effectiveness indicators from growing to match height/margin of multiple effectiveness indicators
}
.multiplierWrapper {
.typeMultiplierWrapper {
width: auto;
margin-right: 2px;
&.multiplierWrapperX3 {
&.typeMultiplierWrapperX3 {
margin-right: -4px;
}
&.multiplierWrapperX4 {
&.typeMultiplierWrapperX4 {
margin-right: -10px;
}
}
& > *,
.multiplierWrapper > * {
.typeWrapper > *,
.typeMultiplierWrapper > * {
flex-basis: unset;
width: 6.75rem;
}
}
}
.isCovered {
position: relative;
&::before {
// inspired by nes.css's `.nes-checkbox`
content: "";
position: absolute;
right: 25px;
bottom: 20px;
z-index: 10;
width: 2px;
height: 2px;
color: $main-success;
box-shadow: 18px 2px, 20px 2px, 16px 4px, 18px 4px, 20px 4px, 2px 6px, 14px 6px, 16px 6px, 2px 8px, 4px 8px, 12px 8px, 14px 8px, 4px 10px, 6px 10px, 10px 10px, 12px 10px, 6px 12px, 8px 12px, 10px 12px, 8px 14px;
}
}

View File

@ -1,7 +1,9 @@
// This file is automatically generated.
// Please do not change this file!
export const indicatorWrapper: string;
export const multiplierWrapper: string;
export const multiplierWrapperX3: string;
export const multiplierWrapperX4: string;
export const isCovered: string;
export const typeMultiplierWrapper: string;
export const typeMultiplierWrapperX3: string;
export const typeMultiplierWrapperX4: string;
export const typeWrapper: string;
export const wrapper: string;

View File

@ -28,6 +28,11 @@
&::after {
@include rounded-box-shadow($primary);
}
&:global(.outline) {
color: $primary;
background-color: $contrast;
}
}
}
}

44
src/ts/app/utils/types.ts Normal file
View File

@ -0,0 +1,44 @@
import POGOProtos from 'pogo-protos';
import { AttackTypeEffectiveness } from 'app/models/Config';
import { CombatMoveStats, ICombatMoveStats, IPokemonMove, TypeEffectiveness } from 'app/models/Pokemon';
import { SelectedCombatMoves } from 'app/components/PokemonExplorer/types';
export const calculateTypeCoverage = (
selectedMoves : SelectedCombatMoves,
movesById : CombatMoveStats,
attackTypeEffectiveness : AttackTypeEffectiveness,
) => {
const calculatedffectiveness : Map<POGOProtos.Enums.PokemonType, TypeEffectiveness> = new Map();
Object.values(selectedMoves).forEach((move) => {
const moveType = getMoveType(move, movesById);
if (moveType !== null) {
const moveEffectiveness = attackTypeEffectiveness.get(moveType);
if (typeof moveEffectiveness !== 'undefined') {
moveEffectiveness.forEach((effectiveness, type) => {
const currentEffectiveness = calculatedffectiveness.get(type);
if (typeof currentEffectiveness === 'undefined' || effectiveness > currentEffectiveness) {
calculatedffectiveness.set(type, effectiveness);
}
});
}
}
});
return calculatedffectiveness;
};
export const getMoveType = (
move : IPokemonMove | null,
movesById : CombatMoveStats,
) => {
let moveStats : ICombatMoveStats | null = null;
if (move !== null) {
moveStats = movesById.get(move.id) || null;
}
if (moveStats !== null) {
return moveStats.type;
}
return null;
};