Repository: CryptoBlades/cryptoblades
File: contracts/PvpArena.sol (Solidity)

Code before:

        isCharacterInArena[characterID] = false;
        isWeaponInArena[weaponID] = false;

        // setting characters, weapons and shield NFTVAR_BUSY to 0
        characters.setNftVar(characterID, 1, 0);
        weapons.setNftVar(weaponID, 1, 0);
    }

    function _getCharacterPowerRoll(Duelist memory character, uint8 opponentTrait)
        private
        view
        returns (uint24)
    {
        Fighter memory fighter = fighterByCharacter[character.ID];
        uint256 weaponID = fighter.weaponID;
        uint256 seed = randoms.getRandomSeedUsingHash(
            characters.ownerOf(character.ID),
            blockhash(block.number - 1)
        );

        int128 bonusShieldStats;
        if (fighter.useShield) {
            bonusShieldStats = _getShieldStats(character.ID);
        }

        (
            ,
            int128 weaponMultFight,
            uint24 weaponBonusPower,
            uint8 weaponTrait
        ) = weapons.getFightData(weaponID, character.trait);

        int128 playerTraitBonus = getPVPTraitBonusAgainst(
            character.trait,
            weaponTrait,
            opponentTrait
        );

        uint24 playerFightPower = Common.getPlayerPower(character.basePower, (weaponMultFight.add(bonusShieldStats)), weaponBonusPower);

        uint256 playerPower = RandomUtil.plusMinus10PercentSeeded(
            playerFightPower,
            seed
        );

        return uint24(playerTraitBonus.mulu(playerPower));
    }

    function getPVPTraitBonusAgainst(
        uint8 characterTrait,

Review comment (suggestion):
These weapon/shield multiplier values are 1-based, meaning the stats will add onto 1, not 0.
Since we will be adding the shield multiplier on top of the weapon, we need to counteract the base value of 1 to only add the stats, otherwise shields will still be too powerful (even a 1star shield with a single stat of 4 would give you +101% on your base character power).
The .sub(1) call would have to be done before the mul(20) step.

This is a very small change so I can handle it right before deployment

Code after:
        }

        isCharacterInArena[characterID] = false;
        isWeaponInArena[weaponID] = false;

        // setting characters, weapons and shield NFTVAR_BUSY to 0
        characters.setNftVar(characterID, 1, 0);
        weapons.setNftVar(weaponID, 1, 0);
    }

    function _getCharacterPowerRoll(Duelist memory character, uint8 opponentTrait)
        private
        view
        returns (uint24)
    {
        Fighter memory fighter = fighterByCharacter[character.ID];
        uint256 weaponID = fighter.weaponID;
        uint256 seed = randoms.getRandomSeedUsingHash(
            characters.ownerOf(character.ID),
            blockhash(block.number - 1)
        );

        int128 bonusShieldStats;
        if (fighter.useShield) {
            // we set bonus shield stats as 0.2
            bonusShieldStats = _getShieldStats(character.ID).mul(20).div(100);
        }

        (
            ,
            int128 weaponMultFight,
            uint24 weaponBonusPower,
            uint8 weaponTrait
        ) = weapons.getFightData(weaponID, character.trait);

        int128 playerTraitBonus = getPVPTraitBonusAgainst(
            character.trait,
            weaponTrait,
            opponentTrait
        );

        uint24 playerFightPower = Common.getPlayerPowerBase100(character.basePower, (weaponMultFight.add(bonusShieldStats)), weaponBonusPower);
        uint256 playerPower = RandomUtil.plusMinus30PercentSeeded(
            playerFightPower,
            seed
        );

        return uint24(playerTraitBonus.mulu(playerPower));
    }

    function getPVPTraitBonusAgainst(