// SPDX-License-Identifier: MIT pragma solidity ^0.8.13; import {Army} from "../src/RaidGeldStructs.sol"; library RaidGeldUtils { uint256 public constant PRECISION = 10000; uint256 constant PRICE_FACTOR = 11500; // base price * (0.00666) * 11 per each next unit uint256 constant MOLOCH_DENIER_PROFIT = 2533; uint256 constant APPRENTICE_PROFIT = 27863; uint256 constant ANOINTED_PROFIT = 306493; uint256 constant CHAMPION_PROFIT = 3371423; // each costs 10 times plus a bit more uint256 constant MOLOCH_DENIER_BASE_COST = 380000; uint256 constant APPRENTICE_BASE_COST = 3420000; uint256 constant ANOINTED_BASE_COST = 30096000; uint256 constant CHAMPION_BASE_COST = 255816000; uint256 constant RISK_BETA = 15e17; function getBossPower(uint8 level) internal pure returns (uint256 power) { require(level <= 7, "Bosses only go to level 7"); if (level == 0) return 9000000; else if (level == 1) return 90000000; else if (level == 2) return 900000000; else if (level == 3) return 9000000000; else if (level == 4) return 90000000000; else if (level == 5) return 900000000000; else if (level == 6) return 9000000000000; } function getBossCumulativeChance(uint8 level) internal pure returns (uint256 chance) { // for boss chances (percent) [99, 89, 80, 70, 62, 51, 40] // where cumulative chance is in the form of 18 precision related to 1e18 require(level <= 7, "Bosses only go to level 7"); if (level == 0) return 99e16; else if (level == 1) return 8811e14; else if (level == 2) return 7048e14; else if (level == 3) return 493416e12; else if (level == 4) return 30591792e10; else if (level == 5) return 1560181392e8; else if (level == 6) return 6240725568e7; } function calculateUnitPrice(uint8 unit, uint16 currentLevel, uint16 units) internal pure returns (uint256) { require(unit <= 3, "No matching unit found"); uint256 rollingPriceCalculation = MOLOCH_DENIER_BASE_COST; uint256 price = 0; if (unit == 1) { rollingPriceCalculation = APPRENTICE_BASE_COST; } else if (unit == 2) { rollingPriceCalculation = ANOINTED_BASE_COST; } else if (unit == 3) { rollingPriceCalculation = CHAMPION_BASE_COST; } // Each level costs 15% more than previous for (uint256 i = 0; i < currentLevel + units; i++) { if (i >= currentLevel) { price += rollingPriceCalculation; } rollingPriceCalculation = rollingPriceCalculation * PRICE_FACTOR / PRECISION; } return price; } function calculateProfitsPerSecond(Army memory army) internal pure returns (uint256) { // Each next unit scales progressivelly better uint256 moloch_denier_profit = army.moloch_denier.level * MOLOCH_DENIER_PROFIT; uint256 apprentice_profit = army.apprentice.level * APPRENTICE_PROFIT; uint256 anointed_profit = army.anointed.level * ANOINTED_PROFIT; uint256 champion_profit = army.champion.level * CHAMPION_PROFIT; return moloch_denier_profit + apprentice_profit + anointed_profit + champion_profit; } // Returns how much Dao Token player is due for winning function calculateBossReward(uint8 bossLevel) internal pure returns (uint256) { return getBossPower(bossLevel) * (getBossCumulativeChance(bossLevel) * 10 / 5) ** 2; } // Calculates whether user survives the fight function calculateBossFight(uint8 bossLevel, uint256 geldBurnt, uint256 prevrandao) internal pure returns (bool) { uint256 bossPower = getBossPower(bossLevel); require(geldBurnt <= bossPower, "Cant try to defeat boss with more than what boss power is"); uint256 random_n = random(prevrandao, 1, 100); // Relative power as in, you can only put in 800 geld to defeat 900 geld boss, // but you will get exponentially worse chances uint256 relativePower = ((geldBurnt ** 2) * 100) / bossPower ** 2; uint256 roll = (random_n * relativePower * PRECISION) / (100 * PRECISION); return roll >= bossPower; } function generate_boss_variants(uint256 prevrandao) internal pure returns (uint8[7] memory boss_variants) { // We shuffle the possible variants so each run is a bit different uint8[6] memory array = [0, 1, 2, 3, 4, 5]; for (uint256 i = array.length - 1; i > 0; i--) { // generate a pseudo-random index based on the prevrandao uint256 j = uint256(keccak256(abi.encodePacked(prevrandao, i))) % (i + 1); // swap elements at i and j (array[i], array[j]) = (array[j], array[i]); } // Last boss is always the same old super Moloch return [array[0], array[1], array[2], array[3], array[4], array[5], 6]; } // TODO: Implement actual randomness function random(uint256 prevrandao, uint256 min, uint256 max) internal pure returns (uint256) { // returns 0 - 100 require(max >= min, "Max must be greater than or equal to min"); uint256 range = max - min + 1; return min + (uint256(keccak256(abi.encodePacked(prevrandao))) % range); } }