140 lines
6.2 KiB
Solidity
140 lines
6.2 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.13;
|
|
|
|
import {Army} from "../src/RaidGeldStructs.sol";
|
|
import {console} from "forge-std/Test.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;
|
|
|
|
uint256 constant NUMBER_OF_BOSSES = 7;
|
|
|
|
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 70488e13;
|
|
else if (level == 3) return 493416e12;
|
|
else if (level == 4) return 30591792e10;
|
|
else if (level == 5) return 1560181392e8;
|
|
else if (level == 6) return 6240725568e7;
|
|
else return 0;
|
|
}
|
|
|
|
function getBossChance(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 99;
|
|
else if (level == 1) return 89;
|
|
else if (level == 2) return 80;
|
|
else if (level == 3) return 70;
|
|
else if (level == 4) return 62;
|
|
else if (level == 5) return 51;
|
|
else if (level == 6) return 40;
|
|
else return 0;
|
|
}
|
|
|
|
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, uint256 baseReward) internal pure returns (uint256) {
|
|
// TODO: This could as well just be pre-calculated
|
|
uint256 cumulativeChance = getBossCumulativeChance(bossLevel); // 0 - 1e18 range
|
|
uint256 rewardMultiplier = ((2 * (1e18 - cumulativeChance)) ** 2) / 1e18;
|
|
return (baseReward * rewardMultiplier);
|
|
}
|
|
|
|
// Calculates whether user survives the fight
|
|
function calculateBossFight(uint8 bossLevel, uint256 geldBurnt, uint256 _randomSeed) internal pure returns (bool) {
|
|
uint256 bossPower = getBossPower(bossLevel);
|
|
uint256 bossRoll = getBossChance(bossLevel);
|
|
require(geldBurnt <= bossPower, "Cant try to defeat boss with more than what boss power is");
|
|
uint256 random_n = random(_randomSeed, 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 = 1e2 - (random_n * relativePower / 1e2);
|
|
return roll < bossRoll;
|
|
}
|
|
|
|
function generate_boss_variants(uint256 _randomSeed) internal pure returns (uint8[7] memory boss_variants) {
|
|
// We shuffle the possible variants so each run is a bit different
|
|
uint8[NUMBER_OF_BOSSES] memory array = [0, 1, 2, 3, 4, 5, 6];
|
|
for (uint256 i = NUMBER_OF_BOSSES - 2; i > 0; i--) {
|
|
// generate a pseudo-random index based on the prevrandao
|
|
uint256 j = uint256(keccak256(abi.encodePacked(_randomSeed, 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;
|
|
}
|
|
|
|
// TODO: Implement actual randomness
|
|
function random(uint256 _randomSeed, uint256 min, uint256 max) internal pure returns (uint256) {
|
|
// returns 0 - 100
|
|
require(max > min, "Max must be greater than min");
|
|
require(max < type(uint256).max, "Dont use largest possible uint");
|
|
uint256 range = max - min + 1;
|
|
return min + (uint256(keccak256(abi.encodePacked(_randomSeed))) % range);
|
|
}
|
|
}
|