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

Code before:
        uint16 xp = getXpGainForFight(playerFightPower, targetPower) * fightMultiplier;
        uint256 tokens = getTokenGainForFight(targetPower, true) * fightMultiplier;


        if (playerRoll < monsterRoll) {
            tokens = 0;
            xp = 0;
        }

        if(tokenRewards[tx.origin] == 0 && tokens > 0) {
            _rewardsClaimTaxTimerStart[tx.origin] = block.timestamp;
        }

        // this may seem dumb but we want to avoid guessing the outcome based on gas estimates!
        tokenRewards[tx.origin] += tokens;
        vars[VAR_UNCLAIMED_SKILL] += tokens;
        vars[VAR_HOURLY_DISTRIBUTION] -= tokens;
        xpRewards[char] += xp;

        vars[VAR_HOURLY_FIGHTS] += fightMultiplier;
        vars[VAR_HOURLY_POWER_SUM] += playerFightPower * fightMultiplier;

        emit FightOutcome(tx.origin, char, wep, (targetPower | ((uint32(traitsCWE) << 8) & 0xFF000000)), playerRoll, monsterRoll, xp, tokens);

        return (tokens.mul(priceOracleSkillPerUsd.currentPrice()).mul(combatTokenChargePercent))
            .div(tokensPrices.tokenPrice().mul(10**18));
    }

    function getMonsterPower(uint32 target) public pure returns (uint24) {
        return uint24(target & 0xFFFFFF);
    }

    function getTokenGainForFight(uint24 monsterPower, bool applyLimit) public view returns (uint256) {
        // monsterPower / avgPower * payPerFight * powerMultiplier
        uint256 amount = ABDKMath64x64.divu(monsterPower, vars[VAR_HOURLY_POWER_AVERAGE])
            .mulu(vars[VAR_HOURLY_PAY_PER_FIGHT]);

        if(amount > vars[VAR_PARAM_MAX_FIGHT_PAYOUT])
            amount = vars[VAR_PARAM_MAX_FIGHT_PAYOUT];
        if(vars[VAR_HOURLY_DISTRIBUTION] < amount * 5 && applyLimit) // the * 5 is a temp measure until we can sync frontend on main
            amount = 0;
        return amount;
    }

    function getXpGainForFight(uint24 playerPower, uint24 monsterPower) internal view returns (uint16) {
        return uint16(ABDKMath64x64.divu(monsterPower, playerPower).mulu(fightXpGain));
    }

    function getPlayerPowerRoll(
        uint24 playerFightPower,
        uint24 traitsCWE,

Review comment (suggestion):
Additional 2 external calls here, that's a lot of gas increase.
BasicPriceOracle is not currently working and skill price is fixed at $62.
How about we track skill price (also update with a bot) in TokensPrices and get the price ratio with one external call to use here, like
```
return (tokens.mul(combatTokenChargePercent).mul(tokensPrices.skillToNativeRatio()).div(1e18)
```

Code after:
        if (playerRoll < monsterRoll) {
            tokens = 0;
            xp = 0;
        }

        // this may seem dumb but we want to avoid guessing the outcome based on gas estimates!
        tokenRewards[tx.origin] += tokens;
        vars[VAR_UNCLAIMED_SKILL] += tokens;
        vars[VAR_HOURLY_DISTRIBUTION] -= tokens;
        xpRewards[char] += xp;
        

        vars[VAR_HOURLY_FIGHTS] += fightMultiplier;
        vars[VAR_HOURLY_POWER_SUM] += playerFightPower * fightMultiplier;

        emit FightOutcome(tx.origin, char, wep, (targetPower | ((uint32(traitsCWE) << 8) & 0xFF000000)), playerRoll, monsterRoll, xp, tokens);
    }

    function getMonsterPower(uint32 target) public pure returns (uint24) {
        return uint24(target & 0xFFFFFF);
    }

    function getTokenGainForFight(uint24 monsterPower, bool applyLimit) public view returns (uint256) {
        // monsterPower / avgPower * payPerFight * powerMultiplier
        uint256 amount = ABDKMath64x64.divu(monsterPower, vars[VAR_HOURLY_POWER_AVERAGE])
            .mulu(vars[VAR_HOURLY_PAY_PER_FIGHT]);

        if(amount > vars[VAR_PARAM_MAX_FIGHT_PAYOUT])
            amount = vars[VAR_PARAM_MAX_FIGHT_PAYOUT];
        if(vars[VAR_HOURLY_DISTRIBUTION] < amount * 5 && applyLimit) // the * 5 is a temp measure until we can sync frontend on main
            amount = 0;
        return amount;
    }

    function getXpGainForFight(uint24 playerPower, uint24 monsterPower) internal view returns (uint16) {
        return uint16(ABDKMath64x64.divu(monsterPower, playerPower).mulu(fightXpGain));
    }

    function getPlayerPowerRoll(
        uint24 playerFightPower,
        uint24 traitsCWE,
        uint256 seed
    ) internal view returns(uint24) {

        uint256 playerPower = RandomUtil.plusMinus10PercentSeeded(playerFightPower,seed);
        return uint24(getPlayerTraitBonusAgainst(traitsCWE).mulu(playerPower));
    }

    function getMonsterPowerRoll(uint24 monsterPower, uint256 seed) internal pure returns(uint24) {
        // roll for fights
        return uint24(RandomUtil.plusMinus10PercentSeeded(monsterPower, seed));