From 72ad9b7e7e7039eeb5d85b1c5ede7d3369079750 Mon Sep 17 00:00:00 2001 From: ECWireless Date: Tue, 30 Jul 2024 08:00:59 -0600 Subject: [PATCH 1/4] Tweak ActionOutcome type name --- packages/client/src/components/ActionsPanel.tsx | 4 ++-- packages/client/src/components/TileDetailsPanel.tsx | 11 ++++------- .../client/src/contexts/MapNavigationContext.tsx | 12 ++++++------ packages/client/src/utils/types.ts | 12 +++++++++++- .../out/CharacterSystem.sol/CharacterSystem.json | 2 +- .../contracts/out/CombatSystem.sol/CombatSystem.json | 2 +- .../out/EquipmentSystem.sol/EquipmentSystem.json | 2 +- packages/contracts/out/IWorld.sol/IWorld.json | 2 +- packages/contracts/out/MapSystem.sol/MapSystem.json | 2 +- 9 files changed, 28 insertions(+), 21 deletions(-) diff --git a/packages/client/src/components/ActionsPanel.tsx b/packages/client/src/components/ActionsPanel.tsx index eeb70aa4f..c25153386 100644 --- a/packages/client/src/components/ActionsPanel.tsx +++ b/packages/client/src/components/ActionsPanel.tsx @@ -56,7 +56,7 @@ export const ActionsPanel = (): JSX.Element => { equippedItems, } = useCharacter(); const { - battleActionOutcomes, + actionOutcomes, currentBattle, isAttacking, isRefreshing: isRefreshingMap, @@ -192,7 +192,7 @@ export const ActionsPanel = (): JSX.Element => { {!currentBattle && actionText} {monsterOponent && - battleActionOutcomes.map((action, i) => { + actionOutcomes.map((action, i) => { if (action.miss) { return ( { } = useMUD(); const { character } = useCharacter(); const { - battleActionOutcomes, + actionOutcomes, currentBattle, isRefreshing, monsterOponent, @@ -47,7 +47,7 @@ export const TileDetailsPanel = (): JSX.Element => { const [isMonsterHit, setIsMonsterHit] = useState(false); useEffect(() => { - if (!(battleActionOutcomes[0] && currentBattle)) return; + if (!(actionOutcomes[0] && currentBattle)) return; const currentBattleTurnKey = 'current-battle-turn'; const currentBattleTurn = localStorage.getItem(currentBattleTurnKey); @@ -58,10 +58,7 @@ export const TileDetailsPanel = (): JSX.Element => { } } - if ( - battleActionOutcomes[battleActionOutcomes.length - 1] - .attackerDamageDelt === '0' - ) + if (actionOutcomes[actionOutcomes.length - 1].attackerDamageDelt === '0') return; setIsMonsterHit(true); @@ -70,7 +67,7 @@ export const TileDetailsPanel = (): JSX.Element => { }, 700); localStorage.setItem(currentBattleTurnKey, currentBattle.currentTurn); - }, [battleActionOutcomes, currentBattle]); + }, [actionOutcomes, currentBattle]); const onInitiateCombat = useCallback( async (monster: Monster) => { diff --git a/packages/client/src/contexts/MapNavigationContext.tsx b/packages/client/src/contexts/MapNavigationContext.tsx index a43910961..8b0b500e4 100644 --- a/packages/client/src/contexts/MapNavigationContext.tsx +++ b/packages/client/src/contexts/MapNavigationContext.tsx @@ -32,8 +32,8 @@ import { useToast } from '../hooks/useToast'; import { GAME_BOARD_PATH } from '../Routes'; import { fetchMetadataFromUri, uriToHttp } from '../utils/helpers'; import { + type ActionOutcomeType, ActionType, - type BattleActionOutcome, type Character, type CombatDetails, type Monster, @@ -42,7 +42,7 @@ import { useCharacter } from './CharacterContext'; import { useMUD } from './MUDContext'; type MapNavigationContextType = { - battleActionOutcomes: BattleActionOutcome[]; + actionOutcomes: ActionOutcomeType[]; currentBattle: CombatDetails | null; isAttacking: boolean; isRefreshing: boolean; @@ -58,7 +58,7 @@ type MapNavigationContextType = { }; const MapNavigationContext = createContext({ - battleActionOutcomes: [], + actionOutcomes: [], currentBattle: null, isAttacking: false, isRefreshing: false, @@ -537,7 +537,7 @@ export const MapNavigationProvider = ({ ], ); - const battleActionOutcomes = useEntityQuery([ + const actionOutcomes = useEntityQuery([ Has(ActionOutcome), HasValue(ActionOutcome, { attackerId: character?.characterId }), ]) @@ -573,14 +573,14 @@ export const MapNavigationProvider = ({ miss: _actionOutcome.miss, timestamp: _actionOutcome.timestamp.toString(), weaponId: _actionOutcome.weaponId.toString(), - } as BattleActionOutcome; + } as ActionOutcomeType; }) .filter(action => action.encounterId === currentBattle?.encounterId); return ( Date: Tue, 30 Jul 2024 08:33:24 -0600 Subject: [PATCH 2/4] Add level up indicators --- packages/client/src/components/Level.tsx | 8 ++- packages/client/src/components/StatsPanel.tsx | 49 ++++++++++++++----- packages/client/src/pages/Character.tsx | 43 +++++++++++----- packages/client/src/utils/theme.ts | 42 +++++++++++++++- 4 files changed, 114 insertions(+), 28 deletions(-) diff --git a/packages/client/src/components/Level.tsx b/packages/client/src/components/Level.tsx index bc5c8cbe6..c74d12c35 100644 --- a/packages/client/src/components/Level.tsx +++ b/packages/client/src/components/Level.tsx @@ -10,6 +10,8 @@ export const Level = ({ return ( 100% - + Level {currentLevel} diff --git a/packages/client/src/components/StatsPanel.tsx b/packages/client/src/components/StatsPanel.tsx index 0511b4cf8..453859a0c 100644 --- a/packages/client/src/components/StatsPanel.tsx +++ b/packages/client/src/components/StatsPanel.tsx @@ -32,19 +32,20 @@ export const StatsPanel = (): JSX.Element => { } = useMUD(); const { character, equippedItems } = useCharacter(); - const nextLevelXpRequirement = useComponentValue( - Levels, - encodeEntity( - { level: 'uint256' }, - { level: BigInt(Number(character?.level ?? 0) + 1) }, - ), - )?.experience; + const nextLevelXpRequirement = + useComponentValue( + Levels, + encodeEntity( + { level: 'uint256' }, + { level: BigInt(Number(character?.level ?? 0) + 1) }, + ), + )?.experience ?? BigInt(0); const levelPercent = useMemo(() => { - if (!(character && nextLevelXpRequirement)) return 0; - return ( - (100 * Number(character.experience)) / Number(nextLevelXpRequirement) - ); + if (!character) return 0; + const percent = + (100 * Number(character.experience)) / Number(nextLevelXpRequirement); + return percent > 100 ? 100 : percent; }, [character, nextLevelXpRequirement]); if (!(character && equippedItems)) { @@ -130,10 +131,34 @@ export const StatsPanel = (): JSX.Element => { - {experience}/{nextLevelXpRequirement?.toString() ?? '0'} + = nextLevelXpRequirement ? 'green' : 'black' + } + fontWeight={ + BigInt(experience) >= nextLevelXpRequirement ? 'bold' : 'normal' + } + > + {BigInt(experience) >= nextLevelXpRequirement + ? nextLevelXpRequirement.toString() + : experience} + + /{nextLevelXpRequirement.toString()} + {BigInt(experience) >= nextLevelXpRequirement && ( + + )} + Equipped Items diff --git a/packages/client/src/pages/Character.tsx b/packages/client/src/pages/Character.tsx index 9a2f5ed91..7907b0ac8 100644 --- a/packages/client/src/pages/Character.tsx +++ b/packages/client/src/pages/Character.tsx @@ -308,19 +308,20 @@ export const CharacterPage = (): JSX.Element => { const maxItemsEquipped = equippedWeapons.length === MAX_EQUIPPED_WEAPONS; - const nextLevelXpRequirement = useComponentValue( - Levels, - encodeEntity( - { level: 'uint256' }, - { level: BigInt(Number(character?.level ?? 0) + 1) }, - ), - )?.experience; + const nextLevelXpRequirement = + useComponentValue( + Levels, + encodeEntity( + { level: 'uint256' }, + { level: BigInt(Number(character?.level ?? 0) + 1) }, + ), + )?.experience ?? BigInt(0); const levelPercent = useMemo(() => { - if (!(character && nextLevelXpRequirement)) return 0; - return ( - (100 * Number(character.experience)) / Number(nextLevelXpRequirement) - ); + if (!character) return 0; + const percent = + (100 * Number(character.experience)) / Number(nextLevelXpRequirement); + return percent > 100 ? 100 : percent; }, [character, nextLevelXpRequirement]); if (isLoadingCharacter) { @@ -472,8 +473,24 @@ export const CharacterPage = (): JSX.Element => { $GOLD - {character.experience}/ - {nextLevelXpRequirement?.toString() ?? '0'} + = nextLevelXpRequirement + ? 'green' + : 'black' + } + fontWeight={ + BigInt(character.experience) >= nextLevelXpRequirement + ? 'bold' + : 'normal' + } + > + {BigInt(character.experience) >= nextLevelXpRequirement + ? nextLevelXpRequirement.toString() + : character.experience} + + /{nextLevelXpRequirement.toString()} diff --git a/packages/client/src/utils/theme.ts b/packages/client/src/utils/theme.ts index e1327de26..633718520 100644 --- a/packages/client/src/utils/theme.ts +++ b/packages/client/src/utils/theme.ts @@ -29,6 +29,32 @@ const Button = { }, }, variants: { + gold: { + bg: 'gold', + border: '2px solid', + borderColor: 'black', + color: 'black', + _active: { + bg: 'rgba(0, 0, 0, 1)', + color: 'white', + _disabled: { + bg: 'rgba(0, 0, 0, 0.7)', + }, + }, + _hover: { + bg: 'rgba(0, 0, 0, 0.8)', + color: 'white', + _disabled: { + bg: 'rgba(0, 0, 0, 0.7)', + }, + }, + _loading: { + bg: 'rgba(0, 0, 0, 0.8)', + _hover: { + bg: 'rgba(0, 0, 0, 0.8)', + }, + }, + }, outline: { border: '2px solid', borderColor: 'grey500', @@ -116,8 +142,20 @@ const Progress = { track: { borderRadius: 5, }, - filledTrack: { - bg: 'black', + }, + defaultProps: { + variant: 'filling', + }, + variants: { + filling: { + filledTrack: { + bg: 'black', + }, + }, + filled: { + filledTrack: { + bg: 'green', + }, }, }, }; From f0c92948a55d3ebc0558d935bfe5526ba28a2cab Mon Sep 17 00:00:00 2001 From: ECWireless Date: Tue, 30 Jul 2024 13:17:14 -0600 Subject: [PATCH 3/4] Add LevelingPanel --- .../client/src/components/LevelingPanel.tsx | 337 ++++++++++++++++++ packages/client/src/components/StatsPanel.tsx | 26 +- packages/client/src/hooks/useToast.ts | 8 +- .../client/src/lib/mud/createSystemCalls.ts | 71 +++- packages/client/src/pages/Character.tsx | 68 ++-- 5 files changed, 449 insertions(+), 61 deletions(-) create mode 100644 packages/client/src/components/LevelingPanel.tsx diff --git a/packages/client/src/components/LevelingPanel.tsx b/packages/client/src/components/LevelingPanel.tsx new file mode 100644 index 000000000..96e5f2aa2 --- /dev/null +++ b/packages/client/src/components/LevelingPanel.tsx @@ -0,0 +1,337 @@ +import { Button, HStack, Text, VStack } from '@chakra-ui/react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { useCharacter } from '../contexts/CharacterContext'; +import { useMUD } from '../contexts/MUDContext'; +import { useToast } from '../hooks/useToast'; +import { type Character } from '../utils/types'; + +export const LevelingPanel = ({ + canLevel, + character, +}: { + canLevel: boolean; + character: Character; +}): JSX.Element => { + const { renderError, renderSuccess, renderWarning } = useToast(); + const { + delegatorAddress, + systemCalls: { levelCharacter }, + } = useMUD(); + const { refreshCharacter } = useCharacter(); + + const [abilityPoints, setAbilityPoints] = useState(0); + const [newAgility, setNewAgility] = useState(character.agility); + const [newIntelligence, setNewIntelligence] = useState( + character.intelligence, + ); + const [newStrength, setNewStrength] = useState(character.strength); + + const [isLeveling, setIsLeveling] = useState(false); + + useEffect(() => { + if (canLevel) { + setAbilityPoints(2); + } + setNewAgility(character.agility); + setNewIntelligence(character.intelligence); + setNewStrength(character.strength); + }, [canLevel, character.agility, character.intelligence, character.strength]); + + const strengthIncreased = useMemo( + () => BigInt(newStrength) > BigInt(character.strength), + [newStrength, character.strength], + ); + + const agilityIncreased = useMemo( + () => BigInt(newAgility) > BigInt(character.agility), + [newAgility, character.agility], + ); + + const intelligenceIncreased = useMemo( + () => BigInt(newIntelligence) > BigInt(character.intelligence), + [newIntelligence, character.intelligence], + ); + + const onDecrementStat = useCallback( + (stat: 'str' | 'agi' | 'int') => { + if (isLeveling) return; + + let replenishAbilityPoint = false; + + switch (stat) { + case 'str': + if (newStrength === character.strength) return; + if (strengthIncreased) { + replenishAbilityPoint = true; + } + if (!replenishAbilityPoint && abilityPoints <= 0) { + renderWarning('You do not have enough ability points.'); + return; + } + + setNewStrength(prev => (BigInt(prev) - BigInt(1)).toString()); + break; + case 'agi': + if (newAgility === character.agility) return; + if (agilityIncreased) { + replenishAbilityPoint = true; + } + if (!replenishAbilityPoint && abilityPoints <= 0) { + renderWarning('You do not have enough ability points.'); + return; + } + + setNewAgility(prev => (BigInt(prev) - BigInt(1)).toString()); + break; + case 'int': + if (newIntelligence === character.intelligence) return; + if (intelligenceIncreased) { + replenishAbilityPoint = true; + } + if (!replenishAbilityPoint && abilityPoints <= 0) { + renderWarning('You do not have enough ability points.'); + return; + } + + setNewIntelligence(prev => (BigInt(prev) - BigInt(1)).toString()); + break; + default: + } + + if (replenishAbilityPoint) { + setAbilityPoints(prev => prev + 1); + } else { + setAbilityPoints(prev => prev - 1); + } + }, + [ + abilityPoints, + agilityIncreased, + character.agility, + character.intelligence, + character.strength, + intelligenceIncreased, + isLeveling, + newAgility, + newIntelligence, + newStrength, + renderWarning, + strengthIncreased, + ], + ); + + const onIncrementStat = useCallback( + (stat: 'str' | 'agi' | 'int') => { + if (isLeveling) return; + if (abilityPoints <= 0) { + renderWarning('You do not have enough ability points.'); + return; + } + + switch (stat) { + case 'str': + setNewStrength(prev => (BigInt(prev) + BigInt(1)).toString()); + break; + case 'agi': + setNewAgility(prev => (BigInt(prev) + BigInt(1)).toString()); + break; + case 'int': + setNewIntelligence(prev => (BigInt(prev) + BigInt(1)).toString()); + break; + default: + } + + setAbilityPoints(prev => prev - 1); + }, + [abilityPoints, isLeveling, renderWarning], + ); + + const onLevelCharacter = useCallback(async () => { + try { + setIsLeveling(true); + if (abilityPoints > 0) { + renderWarning('You have unused ability points'); + return; + } + if (!delegatorAddress) { + throw new Error('Missing delegation.'); + } + + const newStats = { + agility: newAgility, + baseHp: character.baseHp, + currentHp: character.currentHp, + class: character.entityClass, + experience: character.experience, + intelligence: newIntelligence, + level: character.level, + strength: newStrength, + }; + + const { error, success } = await levelCharacter( + character.characterId, + newStats, + ); + + if (error && !success) { + throw new Error(error); + } + + await refreshCharacter(); + renderSuccess('Character leveled up!'); + } catch (e) { + renderError((e as Error)?.message ?? 'Failed to unequip item.', e); + } finally { + setIsLeveling(false); + } + }, [ + abilityPoints, + character.baseHp, + character.characterId, + character.currentHp, + character.entityClass, + character.experience, + character.level, + delegatorAddress, + levelCharacter, + newAgility, + newIntelligence, + newStrength, + refreshCharacter, + renderError, + renderSuccess, + renderWarning, + ]); + + return ( + + + + My Stats + + + Ability Points: {abilityPoints} + + + + Base + + + + HP - Hit + + {character.currentHp}/{character.baseHp} + + + + + STR - Strength + + {strengthIncreased && ( + + )} + + {newStrength} + + {canLevel && ( + + )} + + + + + AGI - Agility + + {agilityIncreased && ( + + )} + + {newAgility} + + {canLevel && ( + + )} + + + + + INT - Intelligence + + {intelligenceIncreased && ( + + )} + + {newIntelligence} + + {canLevel && ( + + )} + + + + {canLevel && ( + + )} + + ); +}; diff --git a/packages/client/src/components/StatsPanel.tsx b/packages/client/src/components/StatsPanel.tsx index 453859a0c..0f572d5b8 100644 --- a/packages/client/src/components/StatsPanel.tsx +++ b/packages/client/src/components/StatsPanel.tsx @@ -32,21 +32,35 @@ export const StatsPanel = (): JSX.Element => { } = useMUD(); const { character, equippedItems } = useCharacter(); + const currentLevelXpRequirement = + useComponentValue( + Levels, + character + ? encodeEntity( + { level: 'uint256' }, + { level: BigInt(Number(character.level) - 1) }, + ) + : undefined, + )?.experience ?? BigInt(0); + const nextLevelXpRequirement = useComponentValue( Levels, - encodeEntity( - { level: 'uint256' }, - { level: BigInt(Number(character?.level ?? 0) + 1) }, - ), + character + ? encodeEntity({ level: 'uint256' }, { level: BigInt(character.level) }) + : undefined, )?.experience ?? BigInt(0); const levelPercent = useMemo(() => { if (!character) return 0; + + const xpSinceLastLevel = + BigInt(character.experience) - currentLevelXpRequirement; + const percent = - (100 * Number(character.experience)) / Number(nextLevelXpRequirement); + (100 * Number(xpSinceLastLevel)) / Number(nextLevelXpRequirement); return percent > 100 ? 100 : percent; - }, [character, nextLevelXpRequirement]); + }, [character, currentLevelXpRequirement, nextLevelXpRequirement]); if (!(character && equippedItems)) { return ( diff --git a/packages/client/src/hooks/useToast.ts b/packages/client/src/hooks/useToast.ts index 92af25ceb..86671e862 100644 --- a/packages/client/src/hooks/useToast.ts +++ b/packages/client/src/hooks/useToast.ts @@ -22,10 +22,12 @@ export const useToast = (): { return; } - // eslint-disable-next-line no-console - console.error(errorLog); + if (errorLog) { + // eslint-disable-next-line no-console + console.error(errorLog); + } - if ((errorLog as Error).message === INSUFFICIENT_FUNDS_MESSAGE) { + if ((errorLog as Error)?.message === INSUFFICIENT_FUNDS_MESSAGE) { toast({ description: (errorLog as Error).message, position: 'top', diff --git a/packages/client/src/lib/mud/createSystemCalls.ts b/packages/client/src/lib/mud/createSystemCalls.ts index a616ba872..78711f475 100644 --- a/packages/client/src/lib/mud/createSystemCalls.ts +++ b/packages/client/src/lib/mud/createSystemCalls.ts @@ -29,7 +29,7 @@ import { } from 'viem'; import { INSUFFICIENT_FUNDS_MESSAGE } from '../../utils/errors'; -import { EncounterType, StatsClasses } from '../../utils/types'; +import { EncounterType, EntityStats, StatsClasses } from '../../utils/types'; import { ClientComponents } from './createClientComponents'; import { SetupNetworkResult } from './setupNetwork'; @@ -290,27 +290,77 @@ export function createSystemCalls( } }; + const levelCharacter = async ( + characterId: Entity, + entityStats: Omit & { + class: StatsClasses; + }, + ): SystemCallReturn => { + try { + const formattedNewStats = { + agility: BigInt(entityStats.agility), + baseHp: BigInt(entityStats.baseHp), + class: entityStats.class, + currentHp: BigInt(entityStats.currentHp), + experience: BigInt(entityStats.experience), + intelligence: BigInt(entityStats.intelligence), + level: BigInt(entityStats.level) + BigInt(1), + strength: BigInt(entityStats.strength), + }; + + await publicClient.simulateContract({ + abi: worldContract.abi, + account: delegatorAddress, + address: worldContract.address, + args: [characterId as `0x${string}`, formattedNewStats], + functionName: 'UD__levelCharacter', + }); + + const tx = await worldContract.write.UD__levelCharacter([ + characterId as `0x${string}`, + formattedNewStats, + ]); + + await waitForTransaction(tx); + + const newLevel = getComponentValueStrict( + Stats, + encodeEntity( + { characterId: 'uint256' }, + { characterId: BigInt(characterId) }, + ), + ).level; + + const success = newLevel === formattedNewStats.level; + + return { + error: success ? undefined : 'Failed to level character.', + success, + }; + } catch (e) { + return { + error: getContractError(e as BaseError), + success: false, + }; + } + }; + const mintCharacter = async ( account: Address, name: string, uri: string, ): SystemCallReturn => { try { - await publicClient.simulateContract({ + const nameHex = stringToHex(name, { size: 32 }); + + const simulatedTx = await publicClient.simulateContract({ abi: worldContract.abi, account: delegatorAddress, address: worldContract.address, - args: [account, stringToHex(name, { size: 32 }), uri], + args: [account, nameHex, uri], functionName: 'UD__mintCharacter', }); - const nameHex = stringToHex(name, { size: 32 }); - const simulatedTx = await worldContract.simulate.UD__mintCharacter([ - account, - nameHex, - uri, - ]); - const characterId = simulatedTx.result; const tx = await worldContract.write.UD__mintCharacter([ @@ -589,6 +639,7 @@ export function createSystemCalls( endTurn, enterGame, equipItems, + levelCharacter, mintCharacter, move, rollStats, diff --git a/packages/client/src/pages/Character.tsx b/packages/client/src/pages/Character.tsx index 7907b0ac8..22d9e9367 100644 --- a/packages/client/src/pages/Character.tsx +++ b/packages/client/src/pages/Character.tsx @@ -38,6 +38,7 @@ import { EditCharacterModal } from '../components/EditCharacterModal'; import { ItemCard } from '../components/ItemCard'; import { ItemEquipModal } from '../components/ItemEquipModal'; import { Level } from '../components/Level'; +import { LevelingPanel } from '../components/LevelingPanel'; import { useCharacter } from '../contexts/CharacterContext'; import { useMUD } from '../contexts/MUDContext'; import { useToast } from '../hooks/useToast'; @@ -308,20 +309,38 @@ export const CharacterPage = (): JSX.Element => { const maxItemsEquipped = equippedWeapons.length === MAX_EQUIPPED_WEAPONS; + const currentLevelXpRequirement = + useComponentValue( + Levels, + character + ? encodeEntity( + { level: 'uint256' }, + { level: BigInt(Number(character.level) - 1) }, + ) + : undefined, + )?.experience ?? BigInt(0); + const nextLevelXpRequirement = useComponentValue( Levels, - encodeEntity( - { level: 'uint256' }, - { level: BigInt(Number(character?.level ?? 0) + 1) }, - ), + character + ? encodeEntity({ level: 'uint256' }, { level: BigInt(character.level) }) + : undefined, )?.experience ?? BigInt(0); const levelPercent = useMemo(() => { if (!character) return 0; + + const xpSinceLastLevel = + BigInt(character.experience) - currentLevelXpRequirement; const percent = - (100 * Number(character.experience)) / Number(nextLevelXpRequirement); + (100 * Number(xpSinceLastLevel)) / Number(nextLevelXpRequirement); return percent > 100 ? 100 : percent; + }, [character, currentLevelXpRequirement, nextLevelXpRequirement]); + + const canLevel = useMemo(() => { + if (!character) return false; + return BigInt(character.experience) >= nextLevelXpRequirement; }, [character, nextLevelXpRequirement]); if (isLoadingCharacter) { @@ -416,42 +435,7 @@ export const CharacterPage = (): JSX.Element => { px={6} rowStart={{ base: 2, sm: 2, md: 2, lg: 1, xl: 1 }} > - - - - My Stats - - - Ability Points: 3 - - - - Base - - - - HP - Hit - - {character.currentHp}/{character.baseHp} - - - - - STR - Strength - {character.strength} - - - - AGI - Agility - {character.agility} - - - - INT - Intelligence - {character.intelligence} - - - + { - Level 1 + Level {character.level} Date: Tue, 30 Jul 2024 13:47:05 -0600 Subject: [PATCH 4/4] Fix ability points bug --- packages/client/src/components/LevelingPanel.tsx | 2 ++ packages/client/src/pages/Character.tsx | 1 + packages/contracts/worlds.json | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/LevelingPanel.tsx b/packages/client/src/components/LevelingPanel.tsx index 96e5f2aa2..454337d44 100644 --- a/packages/client/src/components/LevelingPanel.tsx +++ b/packages/client/src/components/LevelingPanel.tsx @@ -32,6 +32,8 @@ export const LevelingPanel = ({ useEffect(() => { if (canLevel) { setAbilityPoints(2); + } else { + setAbilityPoints(0); } setNewAgility(character.agility); setNewIntelligence(character.intelligence); diff --git a/packages/client/src/pages/Character.tsx b/packages/client/src/pages/Character.tsx index 22d9e9367..430723d4c 100644 --- a/packages/client/src/pages/Character.tsx +++ b/packages/client/src/pages/Character.tsx @@ -340,6 +340,7 @@ export const CharacterPage = (): JSX.Element => { const canLevel = useMemo(() => { if (!character) return false; + if (nextLevelXpRequirement === BigInt(0)) return false; return BigInt(character.experience) >= nextLevelXpRequirement; }, [character, nextLevelXpRequirement]); diff --git a/packages/contracts/worlds.json b/packages/contracts/worlds.json index fe867c3e7..009bbe6e5 100644 --- a/packages/contracts/worlds.json +++ b/packages/contracts/worlds.json @@ -3,7 +3,7 @@ "address": "0xec49f248866357cc892edc7d90475e63c8cc33ee" }, "84532": { - "address": "0xdf2332face5011cf84e9a97e3903ab786cd2ac6e", - "blockNumber": 13130230 + "address": "0x5952c0700e7d46f8d26967ccd4b995a644c38464", + "blockNumber": 13299624 } } \ No newline at end of file