Adds overlays for modal, adds MAX chance geld required
Some checks are pending
CI / Foundry project (push) Waiting to run
Some checks are pending
CI / Foundry project (push) Waiting to run
This commit is contained in:
parent
32bc1177ba
commit
e46d6991a4
@ -2,7 +2,7 @@ import { formatUnits } from "viem"
|
|||||||
import { BossLevel, usePlayer } from "../providers/PlayerProvider"
|
import { BossLevel, usePlayer } from "../providers/PlayerProvider"
|
||||||
import styles from "../styles/Info.module.css"
|
import styles from "../styles/Info.module.css"
|
||||||
import { useEffect, useReducer, useRef } from "react"
|
import { useEffect, useReducer, useRef } from "react"
|
||||||
import { calculateBalance } from "./Counter"
|
import { calculateBalance, toReadable } from "./Counter"
|
||||||
|
|
||||||
export const bossLevelToClass: Record<BossLevel, string> = {
|
export const bossLevelToClass: Record<BossLevel, string> = {
|
||||||
0: styles.boss0,
|
0: styles.boss0,
|
||||||
@ -14,7 +14,7 @@ export const bossLevelToClass: Record<BossLevel, string> = {
|
|||||||
6: styles.boss6,
|
6: styles.boss6,
|
||||||
}
|
}
|
||||||
|
|
||||||
const bossToName: Record<BossLevel, string> = {
|
export const bossToName: Record<BossLevel, string> = {
|
||||||
0: "Gluttonous",
|
0: "Gluttonous",
|
||||||
1: "Slothful",
|
1: "Slothful",
|
||||||
2: "Lusty",
|
2: "Lusty",
|
||||||
@ -70,11 +70,12 @@ const BossInfo = () => {
|
|||||||
const [, render] = useReducer(p => !p, false);
|
const [, render] = useReducer(p => !p, false);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tickInterval = setInterval(() => {
|
const tickInterval = setInterval(() => {
|
||||||
chanceToDefeat.current = getBossChanceToDefeat(boss?.level ?? 0, calculateBalance(
|
const _balance = calculateBalance(
|
||||||
balance ?? BigInt(0),
|
balance ?? BigInt(0),
|
||||||
army?.profit_per_second ?? BigInt(0),
|
army?.profit_per_second ?? BigInt(0),
|
||||||
player?.last_raided_at ?? BigInt(0)
|
player?.last_raided_at ?? BigInt(0)
|
||||||
))
|
);
|
||||||
|
chanceToDefeat.current = getBossChanceToDefeat(boss?.level ?? 0, _balance)
|
||||||
render();
|
render();
|
||||||
}, 100);
|
}, 100);
|
||||||
return () => clearInterval(tickInterval)
|
return () => clearInterval(tickInterval)
|
||||||
@ -86,6 +87,7 @@ const BossInfo = () => {
|
|||||||
<strong>{parseFloat((chanceToDefeat.current * 100).toFixed(2))} % to slay</strong>{" "}
|
<strong>{parseFloat((chanceToDefeat.current * 100).toFixed(2))} % to slay</strong>{" "}
|
||||||
{chanceToDefeat.current == maxChance ? <small className={styles.maxed}>(MAXED)</small> : <small>(Max {maxChance * 100}%)</small>}
|
{chanceToDefeat.current == maxChance ? <small className={styles.maxed}>(MAXED)</small> : <small>(Max {maxChance * 100}%)</small>}
|
||||||
</p>
|
</p>
|
||||||
|
<p><small>{toReadable(bossToBossPower[boss?.level ?? 0])} GELD = max chance</small></p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,39 @@
|
|||||||
import { formatUnits } from "viem";
|
import { formatUnits } from "viem";
|
||||||
import { BossLevel, usePlayer } from "../providers/PlayerProvider";
|
import { usePlayer } from "../providers/PlayerProvider";
|
||||||
import styles from "../styles/Modal.module.css";
|
import styles from "../styles/Modal.module.css";
|
||||||
import { bossToReward } from "./BossInfo";
|
import bgStyles from "../styles/Background.module.css";
|
||||||
|
import { bossToName, bossToReward } from "./BossInfo";
|
||||||
|
import { bossLevelToClass } from "./Boss";
|
||||||
|
|
||||||
|
|
||||||
interface BossOutcomeModalProps {
|
interface BossOutcomeModalProps {
|
||||||
setIsOpen: (val: boolean) => void,
|
setIsOpen: (val: boolean) => void,
|
||||||
outcome: boolean,
|
|
||||||
ascended: boolean,
|
|
||||||
bossLevel: BossLevel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const BossOutcomeModal = ({ setIsOpen, outcome, ascended, bossLevel }: BossOutcomeModalProps) => {
|
const BossOutcomeModal = ({ setIsOpen }: BossOutcomeModalProps) => {
|
||||||
const text = outcome ? "and you won! 🤩" : "and you lost 😔";
|
const { lastBossResult } = usePlayer();
|
||||||
const rewardAmount = parseFloat(parseFloat(formatUnits(bossToReward[bossLevel], 18).toString()).toFixed(4));
|
if (lastBossResult == null) return null;
|
||||||
|
|
||||||
|
const outcome = lastBossResult.reward != BigInt(0);
|
||||||
|
const ascended = lastBossResult.prestigeGained;
|
||||||
|
|
||||||
|
const text = outcome ? <span>and you <strong className={styles.won}>won!</strong> 🤩</span> : <span>and you <strong className={styles.lost}>lost</strong> 😔</span>;
|
||||||
|
const rewardAmount = parseFloat(parseFloat(formatUnits(bossToReward[lastBossResult.level], 18).toString()).toFixed(4));
|
||||||
const rewardText =
|
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>
|
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>
|
: outcome ? <p>You won <strong>{rewardAmount} RGCVII</strong></p>
|
||||||
: <p>Your GELD is now forfeit. Try again 💪 we know you can do it!</p>
|
: <p>Your GELD is now forfeit.<br />Try again 💪 we know you can do it!</p>
|
||||||
|
|
||||||
return <div className={styles.modal}>
|
const bossName = bossToName[lastBossResult.variant];
|
||||||
<h2>You battled a boss</h2>
|
const bossClass = bossLevelToClass[lastBossResult.variant];
|
||||||
<p>{text}</p>
|
|
||||||
|
return <div className={`${styles.modal} ${styles.bossModal}`}>
|
||||||
|
<h2>You battled {bossName} Moloch!</h2>
|
||||||
|
<div className={`${bgStyles.boss} ${bossClass} ${styles.image}`} />
|
||||||
|
<p className={styles.outcome}>{text}</p>
|
||||||
{rewardText}
|
{rewardText}
|
||||||
<div>
|
<div>
|
||||||
<button onClick={() => setIsOpen(false)}>Proceed</button>
|
<button onClick={() => setIsOpen(false)}>Onward!</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { useCallback } from "react";
|
import { useCallback } from "react";
|
||||||
import { usePlayer } from "../providers/PlayerProvider";
|
import { usePlayer } from "../providers/PlayerProvider";
|
||||||
import styles from "../styles/Modal.module.css";
|
import styles from "../styles/Modal.module.css";
|
||||||
|
import bgStyles from "../styles/Background.module.css";
|
||||||
|
|
||||||
interface RegistrationModalProps {
|
interface RegistrationModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
@ -14,13 +15,13 @@ const RegistrationModal = ({ isOpen, setIsOpen }: RegistrationModalProps) => {
|
|||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
}, [register, setIsOpen])
|
}, [register, setIsOpen])
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
return <div className={styles.modal}>
|
return <div className={bgStyles.leaderboardOverlay}><div className={styles.modal}>
|
||||||
<h2>Insert coins to continue</h2>
|
<h2 style={{ textAlign: "center" }}>Insert coins to continue</h2>
|
||||||
<div>
|
<div>
|
||||||
<button onClick={() => onRegister("RGCVII")}>500 RGCVII</button>
|
<button onClick={() => onRegister("RGCVII")}>500 RGCVII</button>
|
||||||
<button onClick={() => onRegister("ETH")}>0.0005 ETH</button>
|
<button onClick={() => onRegister("ETH")}>0.0005 ETH</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div></div>
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RegistrationModal
|
export default RegistrationModal
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
import React, { createContext, ReactNode, useCallback, useContext, useEffect, useState } from 'react'
|
import React, { createContext, ReactNode, useCallback, useContext, useEffect, useRef, useState } from 'react'
|
||||||
import { useAccount, useReadContract, useWriteContract } from 'wagmi'
|
import { useAccount, useReadContract, useWriteContract } from 'wagmi'
|
||||||
import contractAbi from "../../../out/RaidGeld.sol/RaidGeld.json"
|
import contractAbi from "../../../out/RaidGeld.sol/RaidGeld.json"
|
||||||
import { Hash, parseEther } from 'viem'
|
import { Hash, parseEther } from 'viem'
|
||||||
import contracts from '../../contract_address'
|
import contracts from '../../contract_address'
|
||||||
import WaitingForTxModal from '../components/WaitingForTxModal'
|
import WaitingForTxModal from '../components/WaitingForTxModal'
|
||||||
|
import BossOutcomeModal from '../components/BossOutcomeModal'
|
||||||
|
import styles from "../styles/Background.module.css"
|
||||||
|
|
||||||
const { contractAddress, daoTokenAddress } = contracts
|
const { contractAddress, daoTokenAddress } = contracts
|
||||||
const abi = contractAbi.abi
|
const abi = contractAbi.abi
|
||||||
@ -33,11 +35,20 @@ export interface Boss {
|
|||||||
variants: [BossLevel, BossLevel, BossLevel, BossLevel, BossLevel, BossLevel, BossLevel]
|
variants: [BossLevel, BossLevel, BossLevel, BossLevel, BossLevel, BossLevel, BossLevel]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LastBossResult {
|
||||||
|
level: BossLevel;
|
||||||
|
variant: BossLevel;
|
||||||
|
battled_at: bigint;
|
||||||
|
reward: bigint;
|
||||||
|
prestigeGained: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PlayerContextType {
|
export interface PlayerContextType {
|
||||||
isRegistered: boolean,
|
isRegistered: boolean,
|
||||||
player: null | Player,
|
player: null | Player,
|
||||||
army: null | Army,
|
army: null | Army,
|
||||||
boss: null | Boss,
|
boss: null | Boss,
|
||||||
|
lastBossResult: null | LastBossResult,
|
||||||
balance: bigint,
|
balance: bigint,
|
||||||
register: (arg: "ETH" | "RGCVII") => void,
|
register: (arg: "ETH" | "RGCVII") => void,
|
||||||
raid: () => void,
|
raid: () => void,
|
||||||
@ -50,6 +61,7 @@ const PlayerContext = createContext<PlayerContextType>({
|
|||||||
player: null,
|
player: null,
|
||||||
army: null,
|
army: null,
|
||||||
boss: null,
|
boss: null,
|
||||||
|
lastBossResult: null,
|
||||||
balance: BigInt(0),
|
balance: BigInt(0),
|
||||||
register: () => { },
|
register: () => { },
|
||||||
raid: () => { },
|
raid: () => { },
|
||||||
@ -61,7 +73,8 @@ 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);
|
const [bossBattledModalOpen, setBossBattlesModalOpen] = useState(false);
|
||||||
|
const hasFetchedLastBossFirstTime = useRef(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.warn(error)
|
console.warn(error)
|
||||||
@ -126,6 +139,17 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data: lastBossResult } = useReadContract({
|
||||||
|
address: contractAddress,
|
||||||
|
abi,
|
||||||
|
functionName: 'getLastBossResult',
|
||||||
|
args: [address],
|
||||||
|
query: {
|
||||||
|
enabled: isConnected,
|
||||||
|
refetchInterval: 15
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
console.log(balance, player, army, boss)
|
console.log(balance, player, army, boss)
|
||||||
|
|
||||||
const register = useCallback((arg: "RGCVII" | "ETH") => {
|
const register = useCallback((arg: "RGCVII" | "ETH") => {
|
||||||
@ -203,6 +227,16 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
})
|
})
|
||||||
}, [writeContract, resetHashAndCallback])
|
}, [writeContract, resetHashAndCallback])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (lastBossResult != null) {
|
||||||
|
if (hasFetchedLastBossFirstTime.current) {
|
||||||
|
setBossBattlesModalOpen(true);
|
||||||
|
} else {
|
||||||
|
hasFetchedLastBossFirstTime.current = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [lastBossResult])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PlayerContext.Provider value={{
|
<PlayerContext.Provider value={{
|
||||||
isRegistered: isRegistered as boolean,
|
isRegistered: isRegistered as boolean,
|
||||||
@ -210,14 +244,17 @@ const PlayerProvider = ({ children }: { children: ReactNode }) => {
|
|||||||
army: army as Army,
|
army: army as Army,
|
||||||
boss: boss as Boss,
|
boss: boss as Boss,
|
||||||
balance: balance as bigint,
|
balance: balance as bigint,
|
||||||
|
lastBossResult: lastBossResult as LastBossResult,
|
||||||
register,
|
register,
|
||||||
raid,
|
raid,
|
||||||
addUnit,
|
addUnit,
|
||||||
battleWithBoss
|
battleWithBoss
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
|
<div className={`${(txHash || bossBattledModalOpen) ? styles.leaderboardOverlay : ""}`}>
|
||||||
{txHash && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
|
{txHash && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
|
||||||
{bossJustBattled && <WaitingForTxModal hash={txHash} callbackFn={callbackFn} />}
|
{bossBattledModalOpen && <BossOutcomeModal setIsOpen={setBossBattlesModalOpen} />}
|
||||||
|
</div>
|
||||||
</PlayerContext.Provider>
|
</PlayerContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,41 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.bossModal {
|
||||||
|
padding: 32px;
|
||||||
|
z-index: 3;
|
||||||
|
max-width: 100%;
|
||||||
|
width: 500px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 50px;
|
||||||
|
.outcome {
|
||||||
|
font-size: 1.7rem;
|
||||||
|
}
|
||||||
|
.image {
|
||||||
|
position: relative;
|
||||||
|
margin: 0 auto;
|
||||||
|
top: 0;
|
||||||
|
&::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& p {
|
||||||
|
margin: 0.5rem 0;
|
||||||
|
}
|
||||||
|
& button {
|
||||||
|
margin: 1rem;
|
||||||
|
}
|
||||||
|
.lost {
|
||||||
|
color: var(--accent-color);
|
||||||
|
}
|
||||||
|
.won {
|
||||||
|
color: var(--hover-color);
|
||||||
|
}
|
||||||
|
.lost,
|
||||||
|
.won {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
0% {
|
0% {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user