Added LastBossResult struct
This commit is contained in:
parent
7ccc036b2d
commit
32bc1177ba
@ -24,7 +24,7 @@ const bossToName: Record<BossLevel, string> = {
|
|||||||
6: "Greedy",
|
6: "Greedy",
|
||||||
}
|
}
|
||||||
|
|
||||||
const bossToReward: Record<BossLevel, bigint> = {
|
export const bossToReward: Record<BossLevel, bigint> = {
|
||||||
0: BigInt("200000000000000000"),
|
0: BigInt("200000000000000000"),
|
||||||
1: BigInt("28274420000000000000"),
|
1: BigInt("28274420000000000000"),
|
||||||
2: BigInt("174191628800000000000"),
|
2: BigInt("174191628800000000000"),
|
||||||
|
|||||||
31
app/src/components/BossOutcomeModal.tsx
Normal file
31
app/src/components/BossOutcomeModal.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { formatUnits } from "viem";
|
||||||
|
import { BossLevel, usePlayer } from "../providers/PlayerProvider";
|
||||||
|
import styles from "../styles/Modal.module.css";
|
||||||
|
import { bossToReward } from "./BossInfo";
|
||||||
|
|
||||||
|
interface BossOutcomeModalProps {
|
||||||
|
setIsOpen: (val: boolean) => void,
|
||||||
|
outcome: boolean,
|
||||||
|
ascended: boolean,
|
||||||
|
bossLevel: BossLevel
|
||||||
|
}
|
||||||
|
|
||||||
|
const BossOutcomeModal = ({ setIsOpen, outcome, ascended, bossLevel }: BossOutcomeModalProps) => {
|
||||||
|
const text = outcome ? "and you won! 🤩" : "and you lost 😔";
|
||||||
|
const rewardAmount = parseFloat(parseFloat(formatUnits(bossToReward[bossLevel], 18).toString()).toFixed(4));
|
||||||
|
const rewardText =
|
||||||
|
ascended ? <p>You won <strong>{rewardAmount} RGCVII</strong> and <strong>ASCENDED!!!</strong>. This means you beat the bosses and gained a <strong>Prestige level</strong>. Your GELD is now forfeit, but your legend lives on.</p>
|
||||||
|
: outcome ? <p>You won <strong>{rewardAmount} RGCVII</strong></p>
|
||||||
|
: <p>Your GELD is now forfeit. Try again 💪 we know you can do it!</p>
|
||||||
|
|
||||||
|
return <div className={styles.modal}>
|
||||||
|
<h2>You battled a boss</h2>
|
||||||
|
<p>{text}</p>
|
||||||
|
{rewardText}
|
||||||
|
<div>
|
||||||
|
<button onClick={() => setIsOpen(false)}>Proceed</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BossOutcomeModal
|
||||||
@ -61,6 +61,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
const { address, isConnected } = useAccount();
|
const { address, isConnected } = useAccount();
|
||||||
const { writeContract, error } = useWriteContract();
|
const { writeContract, error } = useWriteContract();
|
||||||
const [[txHash, callbackFn], setHashAndCallback] = useState<[Hash | null, () => void]>([null, () => { }])
|
const [[txHash, callbackFn], setHashAndCallback] = useState<[Hash | null, () => void]>([null, () => { }])
|
||||||
|
const [bossJustBattled, setBossJustBattled] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.warn(error)
|
console.warn(error)
|
||||||
@ -133,11 +134,12 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
abi,
|
abi,
|
||||||
address: contractAddress,
|
address: contractAddress,
|
||||||
functionName: 'register_eth',
|
functionName: 'register_eth',
|
||||||
value: parseEther("0.0005"),
|
value: parseEther("0.00005"),
|
||||||
}, {
|
}, {
|
||||||
onSuccess: (hash) => {
|
onSuccess: (hash) => {
|
||||||
setHashAndCallback([hash, resetHashAndCallback])
|
setHashAndCallback([hash, resetHashAndCallback])
|
||||||
}
|
},
|
||||||
|
onError: () => resetHashAndCallback()
|
||||||
})
|
})
|
||||||
} else if (arg === "RGCVII") {
|
} else if (arg === "RGCVII") {
|
||||||
writeContract({
|
writeContract({
|
||||||
@ -156,10 +158,12 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
}, {
|
}, {
|
||||||
onSuccess: (hash) => {
|
onSuccess: (hash) => {
|
||||||
setHashAndCallback([hash, resetHashAndCallback])
|
setHashAndCallback([hash, resetHashAndCallback])
|
||||||
}
|
},
|
||||||
|
onError: () => resetHashAndCallback()
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
}
|
},
|
||||||
|
onError: () => resetHashAndCallback()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [writeContract, resetHashAndCallback])
|
}, [writeContract, resetHashAndCallback])
|
||||||
@ -172,7 +176,8 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
}, {
|
}, {
|
||||||
onSuccess: (hash) => {
|
onSuccess: (hash) => {
|
||||||
setHashAndCallback([hash, resetHashAndCallback])
|
setHashAndCallback([hash, resetHashAndCallback])
|
||||||
}
|
},
|
||||||
|
onError: () => resetHashAndCallback()
|
||||||
})
|
})
|
||||||
}, [writeContract, resetHashAndCallback])
|
}, [writeContract, resetHashAndCallback])
|
||||||
|
|
||||||
@ -190,8 +195,13 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
abi,
|
abi,
|
||||||
address: contractAddress,
|
address: contractAddress,
|
||||||
functionName: 'battle_with_boss',
|
functionName: 'battle_with_boss',
|
||||||
|
}, {
|
||||||
|
onSuccess: (hash) => {
|
||||||
|
setHashAndCallback([hash, () => resetHashAndCallback()])
|
||||||
|
},
|
||||||
|
onError: () => resetHashAndCallback()
|
||||||
})
|
})
|
||||||
}, [writeContract])
|
}, [writeContract, resetHashAndCallback])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlayerContext.Provider value={{
|
<PlayerContext.Provider value={{
|
||||||
@ -207,6 +217,7 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
{txHash && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
|
{txHash && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
|
||||||
|
{bossJustBattled && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
|
||||||
</PlayerContext.Provider>
|
</PlayerContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,6 @@ import { getDefaultConfig } from '@rainbow-me/rainbowkit';
|
|||||||
import {
|
import {
|
||||||
base,
|
base,
|
||||||
baseSepolia,
|
baseSepolia,
|
||||||
sepolia,
|
|
||||||
foundry
|
foundry
|
||||||
} from 'wagmi/chains';
|
} from 'wagmi/chains';
|
||||||
|
|
||||||
@ -13,7 +12,6 @@ export const config = getDefaultConfig({
|
|||||||
baseSepolia,
|
baseSepolia,
|
||||||
foundry,
|
foundry,
|
||||||
base,
|
base,
|
||||||
...(process.env.NEXT_PUBLIC_ENABLE_TESTNETS === 'true' ? [sepolia] : []),
|
|
||||||
],
|
],
|
||||||
ssr: true,
|
ssr: true,
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|||||||
import "@openzeppelin/contracts/access/Ownable.sol";
|
import "@openzeppelin/contracts/access/Ownable.sol";
|
||||||
|
|
||||||
import {RaidGeldUtils} from "../src/RaidGeldUtils.sol";
|
import {RaidGeldUtils} from "../src/RaidGeldUtils.sol";
|
||||||
import {Army, Player, Raider, Boss} from "../src/RaidGeldStructs.sol";
|
import {Army, Player, Raider, Boss, LastBossResult} from "../src/RaidGeldStructs.sol";
|
||||||
import "../src/Constants.sol";
|
import "../src/Constants.sol";
|
||||||
|
|
||||||
contract RaidGeld is ERC20, Ownable, Constants {
|
contract RaidGeld is ERC20, Ownable, Constants {
|
||||||
@ -16,6 +16,7 @@ contract RaidGeld is ERC20, Ownable, Constants {
|
|||||||
mapping(address => Player) private players;
|
mapping(address => Player) private players;
|
||||||
mapping(address => Army) private armies;
|
mapping(address => Army) private armies;
|
||||||
mapping(address => Boss) private bosses;
|
mapping(address => Boss) private bosses;
|
||||||
|
mapping(address => LastBossResult) private lastBossResults;
|
||||||
|
|
||||||
// WETH
|
// WETH
|
||||||
IWETH public immutable weth = IWETH(WETH);
|
IWETH public immutable weth = IWETH(WETH);
|
||||||
@ -44,6 +45,7 @@ contract RaidGeld is ERC20, Ownable, Constants {
|
|||||||
event DaoTokenBuyInAmountSet(address indexed owner, uint256 oldAmount, uint256 newAmount);
|
event DaoTokenBuyInAmountSet(address indexed owner, uint256 oldAmount, uint256 newAmount);
|
||||||
event PrestigeGained(address indexed player, uint32 prestigeLevel);
|
event PrestigeGained(address indexed player, uint32 prestigeLevel);
|
||||||
event BossDefeated(address indexed player, uint8 bossLevel, uint256 earnings);
|
event BossDefeated(address indexed player, uint8 bossLevel, uint256 earnings);
|
||||||
|
event BossBattle(address indexed player, uint8 bossLevel, bool hasWon);
|
||||||
|
|
||||||
// Modifier for functions that should only be available to registered players
|
// Modifier for functions that should only be available to registered players
|
||||||
modifier onlyPlayer() {
|
modifier onlyPlayer() {
|
||||||
@ -106,6 +108,9 @@ contract RaidGeld is ERC20, Ownable, Constants {
|
|||||||
profit_per_second: 0
|
profit_per_second: 0
|
||||||
});
|
});
|
||||||
bosses[_playerAddress] = Boss({level: 0, variants: RaidGeldUtils.generate_boss_variants(block.prevrandao)});
|
bosses[_playerAddress] = Boss({level: 0, variants: RaidGeldUtils.generate_boss_variants(block.prevrandao)});
|
||||||
|
|
||||||
|
// dont change lastBossResult
|
||||||
|
// that only changes after boss battles and on init
|
||||||
}
|
}
|
||||||
|
|
||||||
// New player want to register with ETH
|
// New player want to register with ETH
|
||||||
@ -171,6 +176,11 @@ contract RaidGeld is ERC20, Ownable, Constants {
|
|||||||
return bosses[addr];
|
return bosses[addr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to get the Boss struct
|
||||||
|
function getLastBossResult(address addr) public view returns (LastBossResult memory) {
|
||||||
|
return lastBossResults[addr];
|
||||||
|
}
|
||||||
|
|
||||||
// Quick fn to check if user is registered
|
// Quick fn to check if user is registered
|
||||||
function isRegistered(address addr) public view returns (bool) {
|
function isRegistered(address addr) public view returns (bool) {
|
||||||
return players[addr].created_at != 0;
|
return players[addr].created_at != 0;
|
||||||
@ -248,6 +258,14 @@ contract RaidGeld is ERC20, Ownable, Constants {
|
|||||||
? RaidGeldUtils.getBossPower(boss_to_attack.level)
|
? RaidGeldUtils.getBossPower(boss_to_attack.level)
|
||||||
: balanceOf(msg.sender);
|
: balanceOf(msg.sender);
|
||||||
bool hasWonBattle = RaidGeldUtils.calculateBossFight(boss_to_attack.level, geld_to_burn, block.prevrandao);
|
bool hasWonBattle = RaidGeldUtils.calculateBossFight(boss_to_attack.level, geld_to_burn, block.prevrandao);
|
||||||
|
emit BossBattle(msg.sender, boss_to_attack.level, hasWonBattle);
|
||||||
|
lastBossResults[msg.sender] = LastBossResult({
|
||||||
|
battled_at: block.timestamp,
|
||||||
|
level: boss_to_attack.level,
|
||||||
|
variant: boss_to_attack.variants[boss_to_attack.level],
|
||||||
|
prestigeGained: false,
|
||||||
|
reward: 0
|
||||||
|
});
|
||||||
if (hasWonBattle) {
|
if (hasWonBattle) {
|
||||||
// Burn geld, send some sweet DAO Token and continue
|
// Burn geld, send some sweet DAO Token and continue
|
||||||
_burn(msg.sender, geld_to_burn);
|
_burn(msg.sender, geld_to_burn);
|
||||||
@ -256,11 +274,14 @@ contract RaidGeld is ERC20, Ownable, Constants {
|
|||||||
daoToken.transfer(msg.sender, reward);
|
daoToken.transfer(msg.sender, reward);
|
||||||
emit BossDefeated(msg.sender, boss_to_attack.level, reward);
|
emit BossDefeated(msg.sender, boss_to_attack.level, reward);
|
||||||
|
|
||||||
|
lastBossResults[msg.sender].reward = reward;
|
||||||
|
|
||||||
if (boss_to_attack.level == 6) {
|
if (boss_to_attack.level == 6) {
|
||||||
// User ascends! Moloch is defeated, user can start a new run
|
// User ascends! Moloch is defeated, user can start a new run
|
||||||
players[msg.sender].prestige_level += 1;
|
players[msg.sender].prestige_level += 1;
|
||||||
emit PrestigeGained(msg.sender, players[msg.sender].prestige_level);
|
emit PrestigeGained(msg.sender, players[msg.sender].prestige_level);
|
||||||
player_dies(msg.sender);
|
player_dies(msg.sender);
|
||||||
|
lastBossResults[msg.sender].prestigeGained = true;
|
||||||
return [hasWonBattle, true /* New prestige level! */ ];
|
return [hasWonBattle, true /* New prestige level! */ ];
|
||||||
} else {
|
} else {
|
||||||
// else go to next boss
|
// else go to next boss
|
||||||
@ -268,6 +289,7 @@ contract RaidGeld is ERC20, Ownable, Constants {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Whoops u died, boss defeated you
|
// Whoops u died, boss defeated you
|
||||||
|
lastBossResults[msg.sender].reward = 0;
|
||||||
player_dies(msg.sender);
|
player_dies(msg.sender);
|
||||||
}
|
}
|
||||||
return [hasWonBattle, false /* hasnt gotten prestige level */ ];
|
return [hasWonBattle, false /* hasnt gotten prestige level */ ];
|
||||||
|
|||||||
@ -28,3 +28,11 @@ struct Boss {
|
|||||||
uint8 level;
|
uint8 level;
|
||||||
uint8[7] variants;
|
uint8[7] variants;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct LastBossResult {
|
||||||
|
uint256 battled_at;
|
||||||
|
uint256 reward;
|
||||||
|
uint8 level;
|
||||||
|
uint8 variant;
|
||||||
|
bool prestigeGained;
|
||||||
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ pragma solidity ^0.8.13;
|
|||||||
|
|
||||||
import {Test, console} from "forge-std/Test.sol";
|
import {Test, console} from "forge-std/Test.sol";
|
||||||
import {stdStorage, StdStorage} from "forge-std/Test.sol";
|
import {stdStorage, StdStorage} from "forge-std/Test.sol";
|
||||||
import {RaidGeld, Army, Player, Boss} from "../src/RaidGeld.sol";
|
import {RaidGeld, Army, Player, Boss, LastBossResult} from "../src/RaidGeld.sol";
|
||||||
import "../src/RaidGeldUtils.sol";
|
import "../src/RaidGeldUtils.sol";
|
||||||
import {Constants} from "../src/Constants.sol";
|
import {Constants} from "../src/Constants.sol";
|
||||||
|
|
||||||
@ -283,6 +283,13 @@ contract raid_geldTest is Test, Constants {
|
|||||||
|
|
||||||
uint256 afterBossDaoBalance = raid_geld.daoToken().balanceOf(player1);
|
uint256 afterBossDaoBalance = raid_geld.daoToken().balanceOf(player1);
|
||||||
uint256 afterBossContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
|
uint256 afterBossContractBalance = raid_geld.daoToken().balanceOf(address(raid_geld));
|
||||||
|
LastBossResult memory bossResult = raid_geld.getLastBossResult(player1);
|
||||||
|
|
||||||
|
assertEq(bossResult.battled_at, block.timestamp);
|
||||||
|
assertEq(bossResult.reward, afterBossDaoBalance - initialDaoBalance);
|
||||||
|
assertEq(bossResult.level, boss.level);
|
||||||
|
assertEq(bossResult.variant, boss.variants[boss.level]);
|
||||||
|
assertEq(bossResult.prestigeGained, false);
|
||||||
|
|
||||||
// User should receive funs, contract should lose them
|
// User should receive funs, contract should lose them
|
||||||
assertLt(initialDaoBalance, afterBossDaoBalance);
|
assertLt(initialDaoBalance, afterBossDaoBalance);
|
||||||
@ -306,6 +313,7 @@ contract raid_geldTest is Test, Constants {
|
|||||||
registerPlayerWithDaoToken();
|
registerPlayerWithDaoToken();
|
||||||
raid_geld.addUnit(0, 1);
|
raid_geld.addUnit(0, 1);
|
||||||
|
|
||||||
|
Boss memory boss = raid_geld.getBoss(player1);
|
||||||
bool[2] memory results = raid_geld.battle_with_boss();
|
bool[2] memory results = raid_geld.battle_with_boss();
|
||||||
// Should lose with just starting GELD
|
// Should lose with just starting GELD
|
||||||
assertEq(results[0], false);
|
assertEq(results[0], false);
|
||||||
@ -321,6 +329,13 @@ contract raid_geldTest is Test, Constants {
|
|||||||
assertEq(raid_geld.balanceOf(player1), 0);
|
assertEq(raid_geld.balanceOf(player1), 0);
|
||||||
// Units should reset
|
// Units should reset
|
||||||
assertEq(army.moloch_denier.level, 0);
|
assertEq(army.moloch_denier.level, 0);
|
||||||
|
|
||||||
|
LastBossResult memory bossResult = raid_geld.getLastBossResult(player1);
|
||||||
|
assertEq(bossResult.battled_at, block.timestamp);
|
||||||
|
assertEq(bossResult.reward, 0);
|
||||||
|
assertEq(bossResult.level, boss.level);
|
||||||
|
assertEq(bossResult.variant, boss.variants[boss.level]);
|
||||||
|
assertEq(bossResult.prestigeGained, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function test_08_player_who_lost_can_restart() public {
|
function test_08_player_who_lost_can_restart() public {
|
||||||
@ -388,6 +403,8 @@ contract raid_geldTest is Test, Constants {
|
|||||||
if (results[0] == true && results[1] == true) {
|
if (results[0] == true && results[1] == true) {
|
||||||
success = true;
|
success = true;
|
||||||
Player memory player = raid_geld.getPlayer(player1);
|
Player memory player = raid_geld.getPlayer(player1);
|
||||||
|
LastBossResult memory bossResult = raid_geld.getLastBossResult(player1);
|
||||||
|
assertEq(bossResult.prestigeGained, true);
|
||||||
vm.assertEq(player.prestige_level, 1);
|
vm.assertEq(player.prestige_level, 1);
|
||||||
vm.assertEq(player.n_runs, tries);
|
vm.assertEq(player.n_runs, tries);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user