diff --git a/indexer/env-goerli b/indexer/env-goerli
index 252c34f71..97e29d3fc 100644
--- a/indexer/env-goerli
+++ b/indexer/env-goerli
@@ -1,3 +1,3 @@
-GAME="0x06be55931ec7e63fe429d677677b03302f724b966dde8241cb08c2da76ed5895"
+GAME="0x055b3d17ac13c34e758e58c522724edab81163abe4ca1a5b2acc06b258e5d783"
START=873000
MONGO_CONNECTION_STRING="mongodb://mongo:mongo@indexer-mongo-1:27017"
diff --git a/indexer/src/adventurers.ts b/indexer/src/adventurers.ts
index a8713417f..0f483dd81 100644
--- a/indexer/src/adventurers.ts
+++ b/indexer/src/adventurers.ts
@@ -99,7 +99,6 @@ export default function transform({ header, events }: Block) {
case START_GAME: {
console.log("START_GAME", "->", "ADVENTURER UPDATES");
const { value } = parseStartGame(event.data, 0);
- console.log(value);
const as = value.adventurerState;
const am = value.adventurerMeta;
return [
diff --git a/ui/src/app/api/api.ts b/ui/src/app/api/api.ts
index 30590610a..79366c955 100644
--- a/ui/src/app/api/api.ts
+++ b/ui/src/app/api/api.ts
@@ -1,9 +1,33 @@
-import { useAccount } from "@starknet-react/core";
+import { getRPCUrl } from "../lib/constants";
interface MintEthProps {
address: string;
}
+export const getBlock = async (blockNumber: number) => {
+ const rpcUrl = getRPCUrl();
+ try {
+ const requestBody = {
+ jsonrpc: "2.0",
+ method: "starknet_getBlockWithTxHashes",
+ params: [{ block_number: blockNumber }],
+ id: 1,
+ };
+ const response = await fetch(rpcUrl, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(requestBody),
+ });
+
+ const data = await response.json();
+ return data.result;
+ } catch (error) {
+ console.error("Error posting data:", error);
+ }
+};
+
export const mintEth = async ({ address }: MintEthProps) => {
try {
const requestBody = {
diff --git a/ui/src/app/components/ArcadeDialog.tsx b/ui/src/app/components/ArcadeDialog.tsx
index 0ed9d4d93..9b815a260 100644
--- a/ui/src/app/components/ArcadeDialog.tsx
+++ b/ui/src/app/components/ArcadeDialog.tsx
@@ -109,7 +109,6 @@ export const ArcadeDialog = () => {
const getAccountBalances = async (account: string) => {
const balances = await fetchBalanceWithRetry(account);
- console.log(balances);
setArcadeBalances({
...arcadebalances,
[account]: {
diff --git a/ui/src/app/components/CountDown.tsx b/ui/src/app/components/CountDown.tsx
index 56ebdeabd..ab14e4ea0 100644
--- a/ui/src/app/components/CountDown.tsx
+++ b/ui/src/app/components/CountDown.tsx
@@ -7,9 +7,9 @@ const formatTime = (totalSeconds: number) => {
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds - hours * 3600) / 60);
const seconds = totalSeconds % 60;
- return `${hours.toString().padStart(2, "0")}:${minutes
+ return `${minutes.toString().padStart(2, "0")}:${seconds
.toString()
- .padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
+ .padStart(2, "0")}`;
};
export const HealthCountDown = ({ health }: any) => {
@@ -100,10 +100,14 @@ export const PenaltyCountDown = ({
};
export interface EntropyCountDownProps {
- targetTime: number;
+ targetTime: number | null;
+ countDownExpired: () => void;
}
-export const EntropyCountDown = ({ targetTime }: EntropyCountDownProps) => {
+export const EntropyCountDown = ({
+ targetTime,
+ countDownExpired,
+}: EntropyCountDownProps) => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
if (targetTime) {
@@ -111,6 +115,12 @@ export const EntropyCountDown = ({ targetTime }: EntropyCountDownProps) => {
const currentTime = new Date().getTime();
const timeRemaining = targetTime - currentTime;
setSeconds(Math.floor(timeRemaining / 1000));
+
+ if (timeRemaining <= 0) {
+ countDownExpired(); // Call the countDownExpired function when countdown expires
+ } else {
+ setSeconds(Math.floor(timeRemaining / 1000));
+ }
};
updateCountdown();
@@ -122,12 +132,27 @@ export const EntropyCountDown = ({ targetTime }: EntropyCountDownProps) => {
}
}, [targetTime]);
return (
-
- {seconds > 0 && (
-
- {formatTime(seconds)}
-
- )}
+
+
+ {targetTime ? (
+ <>
+ Session Starts in
+
+ {seconds === 0 ? "GO" : formatTime(seconds)}
+
+ >
+ ) : (
+
+ Loading
+
+ )}
+
);
};
diff --git a/ui/src/app/components/adventurer/InventoryDisplay.tsx b/ui/src/app/components/adventurer/InventoryDisplay.tsx
index 01ed410b6..9a24f4dbb 100644
--- a/ui/src/app/components/adventurer/InventoryDisplay.tsx
+++ b/ui/src/app/components/adventurer/InventoryDisplay.tsx
@@ -77,7 +77,6 @@ export const InventoryCard = ({
const handleEquipItems = (item: string) => {
const formattedNewEquipItems = handleCheckSameSlot(slot, equipItems);
- console.log(equipItems);
const newEquipItems = [
...formattedNewEquipItems,
getKeyFromValue(gameData.ITEMS, item) ?? "",
diff --git a/ui/src/app/components/animations/RowLoadre.tsx b/ui/src/app/components/animations/RowLoadre.tsx
new file mode 100644
index 000000000..f3b62137a
--- /dev/null
+++ b/ui/src/app/components/animations/RowLoadre.tsx
@@ -0,0 +1,40 @@
+import React, { useState, useEffect } from "react";
+
+const RowLoader: React.FC = () => {
+ const cols = 6; // Change to 6 columns
+ const [loaderData, setLoaderData] = useState
(Array(cols).fill(-1));
+
+ useEffect(() => {
+ const row = loaderData;
+ const randomStartX = Math.floor(Math.random() * cols);
+
+ row[randomStartX] = 0; // Set the initial square to 0
+
+ let order = 0;
+ for (let i = 0; i < cols; i++) {
+ row[i] = order++;
+ }
+
+ setLoaderData([...row]);
+ }, []);
+
+ return (
+
+
+ {loaderData.map((order, colIndex) => (
+
+ ))}
+
+
+ );
+};
+
+export default RowLoader;
diff --git a/ui/src/app/components/interlude/Hints.tsx b/ui/src/app/components/interlude/Hints.tsx
new file mode 100644
index 000000000..899c462c6
--- /dev/null
+++ b/ui/src/app/components/interlude/Hints.tsx
@@ -0,0 +1,43 @@
+import { useEffect, useState } from "react";
+import { ActionsTutorial } from "../tutorial/ActionsTutorial";
+import { AdventurerTutorial } from "../tutorial/AdventurerTutorial";
+import { BeastTutorial } from "../tutorial/BeastTutorial";
+import { UpgradeTutorial } from "../tutorial/UpgradeTutorial";
+import RowLoader from "../animations/RowLoadre";
+
+export default function Hints() {
+ const [currentIndex, setCurrentIndex] = useState(0);
+ const tutorials = [
+ ,
+ ,
+ ,
+ ,
+ ];
+ useEffect(() => {
+ if (currentIndex < tutorials.length - 1) {
+ const timer = setTimeout(() => {
+ setCurrentIndex((prev) => prev + 1);
+ }, 10000);
+ return () => {
+ clearTimeout(timer);
+ };
+ } else if (currentIndex === tutorials.length - 1) {
+ const timer = setTimeout(() => {
+ setCurrentIndex(0);
+ }, 10000);
+ return () => clearTimeout(timer);
+ }
+ }, [currentIndex]);
+
+ return (
+
+
Hints
+
+
+
+
+
{tutorials[currentIndex]}
+
+
+ );
+}
diff --git a/ui/src/app/components/interlude/Lobby.tsx b/ui/src/app/components/interlude/Lobby.tsx
index 7b57deafe..8f66ae480 100644
--- a/ui/src/app/components/interlude/Lobby.tsx
+++ b/ui/src/app/components/interlude/Lobby.tsx
@@ -64,7 +64,11 @@ export default function Lobby() {
- Adventurer |
+ Name |
+ Account |
+ Death Toll |
+ Best Run |
+ Blocks Left |
@@ -74,6 +78,7 @@ export default function Lobby() {
key={index}
adventurer={adventurer}
handleRowSelected={handleRowSelected}
+ currentBlock={blockData?.block_number!}
/>
)
)}
diff --git a/ui/src/app/components/interlude/LobbyRow.tsx b/ui/src/app/components/interlude/LobbyRow.tsx
index e6679e001..37893613e 100644
--- a/ui/src/app/components/interlude/LobbyRow.tsx
+++ b/ui/src/app/components/interlude/LobbyRow.tsx
@@ -6,9 +6,14 @@ import { soundSelector } from "@/app/hooks/useUiSound";
interface LobbyRowProps {
adventurer: Adventurer;
handleRowSelected: (id: number) => void;
+ currentBlock: number;
}
-const LobbyRow = ({ adventurer, handleRowSelected }: LobbyRowProps) => {
+const LobbyRow = ({
+ adventurer,
+ handleRowSelected,
+ currentBlock,
+}: LobbyRowProps) => {
const { play: clickPlay } = useUiSounds(soundSelector.click);
const adventurersByOwner = useQueriesStore(
(state) => state.data.adventurersByOwnerQuery?.adventurers ?? []
@@ -16,6 +21,7 @@ const LobbyRow = ({ adventurer, handleRowSelected }: LobbyRowProps) => {
const ownedAdventurer = adventurersByOwner.some(
(a) => a.id === adventurer.id
);
+
return (
{
}}
>
{`${adventurer.name} - ${adventurer.id}`} |
+ {adventurer.owner} |
+ 10 |
+ 100 XP |
+ {adventurer?.revealBlock! - currentBlock} |
);
};
diff --git a/ui/src/app/components/leaderboard/ScoreTable.tsx b/ui/src/app/components/leaderboard/ScoreTable.tsx
index 7bdb15e9c..8408b93af 100644
--- a/ui/src/app/components/leaderboard/ScoreTable.tsx
+++ b/ui/src/app/components/leaderboard/ScoreTable.tsx
@@ -32,8 +32,6 @@ const ScoreLeaderboardTable = ({
const scoreIds = scores?.map((score) => score.id ?? 0);
- console.log(scoreIds);
-
const scoresData = useCustomQuery("topScoresQuery", getScoresInList, {
ids: scoreIds,
});
diff --git a/ui/src/app/components/tutorial/ActionsTutorial.tsx b/ui/src/app/components/tutorial/ActionsTutorial.tsx
index e20cd57df..6c3001fdf 100644
--- a/ui/src/app/components/tutorial/ActionsTutorial.tsx
+++ b/ui/src/app/components/tutorial/ActionsTutorial.tsx
@@ -1,6 +1,6 @@
export const ActionsTutorial = () => {
return (
-
+
Explore
During your exploration, you will encounter a number of things. These
diff --git a/ui/src/app/components/tutorial/AdventurerTutorial.tsx b/ui/src/app/components/tutorial/AdventurerTutorial.tsx
index 5e3539ffe..ab7a56126 100644
--- a/ui/src/app/components/tutorial/AdventurerTutorial.tsx
+++ b/ui/src/app/components/tutorial/AdventurerTutorial.tsx
@@ -1,6 +1,6 @@
export const AdventurerTutorial = () => {
return (
-
+
Welcome to Loot Survivor!
{/*
Create an Adventurer
*/}
diff --git a/ui/src/app/components/tutorial/BeastTutorial.tsx b/ui/src/app/components/tutorial/BeastTutorial.tsx
index 23295c19b..c919eb16d 100644
--- a/ui/src/app/components/tutorial/BeastTutorial.tsx
+++ b/ui/src/app/components/tutorial/BeastTutorial.tsx
@@ -1,6 +1,6 @@
export const BeastTutorial = () => {
return (
-
+
Beast
Oh dear! You've stumbled upon a beast! A potential ambush lurks.
diff --git a/ui/src/app/components/tutorial/EfficaciesTutorial.tsx b/ui/src/app/components/tutorial/EfficaciesTutorial.tsx
new file mode 100644
index 000000000..e69de29bb
diff --git a/ui/src/app/components/tutorial/UpgradeTutorial.tsx b/ui/src/app/components/tutorial/UpgradeTutorial.tsx
index cdc1b6a73..6e8ceea52 100644
--- a/ui/src/app/components/tutorial/UpgradeTutorial.tsx
+++ b/ui/src/app/components/tutorial/UpgradeTutorial.tsx
@@ -1,6 +1,6 @@
export const UpgradeTutorial = () => {
return (
-
+
Level Up
Health Potions
diff --git a/ui/src/app/containers/AdventurerScreen.tsx b/ui/src/app/containers/AdventurerScreen.tsx
index 6578468ef..55aeaec3a 100644
--- a/ui/src/app/containers/AdventurerScreen.tsx
+++ b/ui/src/app/containers/AdventurerScreen.tsx
@@ -33,7 +33,6 @@ export default function AdventurerScreen({
const adventurers = useQueriesStore(
(state) => state.data.adventurersByOwnerQuery?.adventurers || []
);
- console.log(adventurers);
const resetData = useQueriesStore((state) => state.resetData);
const startOption = useUIStore((state) => state.startOption);
const setStartOption = useUIStore((state) => state.setStartOption);
diff --git a/ui/src/app/containers/BeastScreen.tsx b/ui/src/app/containers/BeastScreen.tsx
index c477a1d1f..c0bef31cd 100644
--- a/ui/src/app/containers/BeastScreen.tsx
+++ b/ui/src/app/containers/BeastScreen.tsx
@@ -12,6 +12,8 @@ import useUIStore from "../hooks/useUIStore";
import useCustomQuery from "../hooks/useCustomQuery";
import { getLastestEntropy } from "../hooks/graphql/queries";
import InterludeScreen from "./InterludeScreen";
+import { getBlock } from "../api/api";
+import { useBlock } from "@starknet-react/core";
interface BeastScreenProps {
attack: (...args: any[]) => any;
@@ -23,7 +25,6 @@ interface BeastScreenProps {
* @description Provides the beast screen for adventurer battles.
*/
export default function BeastScreen({ attack, flee }: BeastScreenProps) {
- const [nextEntropyTime, setNextEntropyTime] = useState(0);
const adventurer = useAdventurerStore((state) => state.adventurer);
const loading = useLoadingStore((state) => state.loading);
const estimatingFee = useUIStore((state) => state.estimatingFee);
@@ -39,6 +40,10 @@ export default function BeastScreen({ attack, flee }: BeastScreenProps) {
(state) => state.data.battlesByBeastQuery?.battles || []
);
+ const { data: blockData } = useBlock({
+ refetchInterval: false,
+ });
+
const [buttonText, setButtonText] = useState("Flee");
const handleMouseEnter = () => {
@@ -148,38 +153,15 @@ export default function BeastScreen({ attack, flee }: BeastScreenProps) {
);
- const latestEntropyData = useCustomQuery(
- "latestEntropyQuery",
- getLastestEntropy,
- undefined
- );
-
- useEffect(() => {
- if (latestEntropyData) {
- setData("latestEntropyQuery", latestEntropyData);
- const nextEntropyRotationBlock = adventurer?.revealBlock!;
- const adventurerStartBlock = adventurer?.startBlock!;
- const blockDifference = nextEntropyRotationBlock - adventurerStartBlock;
- const blocksPerHour = latestEntropyData.entropy[0].blocksPerHour;
- const blocksPerMillisecond = blocksPerHour / (60 * 60 * 1000);
- const secondsUntilNextEntropy = blockDifference / blocksPerMillisecond;
- const adventurerCreatedTime = new Date(
- adventurer?.createdTime!
- ).getTime();
- const nextEntropyTime = adventurerCreatedTime + secondsUntilNextEntropy;
- setNextEntropyTime(nextEntropyTime);
- }
- }, [latestEntropyData]);
-
- const currentTime = new Date().getTime();
-
if (showBattleLog) {
return
;
}
return (
-
+ {blockData?.block_number! < adventurer?.revealBlock! && (
+
+ )}
{hasBeast ? (
diff --git a/ui/src/app/containers/InterludeScreen.tsx b/ui/src/app/containers/InterludeScreen.tsx
index 76ace05e0..074b554b4 100644
--- a/ui/src/app/containers/InterludeScreen.tsx
+++ b/ui/src/app/containers/InterludeScreen.tsx
@@ -1,15 +1,62 @@
+import { useState, useEffect } from "react";
+import { useBlock } from "@starknet-react/core";
import { EntropyCountDown } from "../components/CountDown";
+import Hints from "../components/interlude/Hints";
+import { fetchAverageBlockTime } from "../lib/utils";
+import useAdventurerStore from "../hooks/useAdventurerStore";
-interface InterludeScreenProps {
- nextEntropyTime: number;
-}
+export default function InterludeScreen() {
+ const { adventurer } = useAdventurerStore();
+ const [fetchedAverageBlockTime, setFetchedAverageBlockTime] = useState(false);
+ const [averageBlockTime, setAverageBlockTime] = useState(0);
+ const [nextEntropyTime, setNextEntropyTime] = useState
(null);
+ const [countDownExpired, setCountDownExpired] = useState(false);
+
+ const { data: blockData } = useBlock({
+ refetchInterval: false,
+ });
+
+ const fetchData = async () => {
+ const result = await fetchAverageBlockTime(blockData?.block_number!, 10);
+ setAverageBlockTime(result!);
+ setFetchedAverageBlockTime(true);
+ };
+
+ const getNextEntropyTime = () => {
+ const nextBlockHashBlock = adventurer?.revealBlock!;
+ const adventurerStartBlock = adventurer?.startBlock!;
+ const blockDifference = nextBlockHashBlock - adventurerStartBlock;
+ const secondsUntilNextEntropy = blockDifference * averageBlockTime;
+ const adventurerCreatedTime = new Date(adventurer?.createdTime!).getTime();
+ const nextEntropyTime =
+ adventurerCreatedTime + secondsUntilNextEntropy * 1000;
+ setNextEntropyTime(nextEntropyTime);
+ };
+
+ useEffect(() => {
+ if (fetchedAverageBlockTime) {
+ getNextEntropyTime();
+ } else {
+ fetchData();
+ }
+ }, [fetchedAverageBlockTime]);
-export default function InterludeScreen({
- nextEntropyTime,
-}: InterludeScreenProps) {
return (
-
-
-
+ <>
+ {!countDownExpired && (
+ <>
+
+
+
setCountDownExpired(true)}
+ />
+
+
+
+
+ >
+ )}
+ >
);
}
diff --git a/ui/src/app/lib/constants.ts b/ui/src/app/lib/constants.ts
index 8d0dea133..f5faefbe3 100644
--- a/ui/src/app/lib/constants.ts
+++ b/ui/src/app/lib/constants.ts
@@ -39,7 +39,7 @@ export function getContracts() {
case "goerli":
return {
eth: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
- game: "0x06be55931ec7e63fe429d677677b03302f724b966dde8241cb08c2da76ed5895",
+ game: "0x055b3d17ac13c34e758e58c522724edab81163abe4ca1a5b2acc06b258e5d783",
lords:
"0x05e367ac160e5f90c5775089b582dfc987dd148a5a2f977c49def2a6644f724b",
};
diff --git a/ui/src/app/lib/utils/index.ts b/ui/src/app/lib/utils/index.ts
index 14e735fc5..0a64e2b16 100644
--- a/ui/src/app/lib/utils/index.ts
+++ b/ui/src/app/lib/utils/index.ts
@@ -13,6 +13,7 @@ import {
import { z } from "zod";
import { deathMessages, FEE_CHECK_BALANCE } from "../constants";
import { Call, AccountInterface, Account } from "starknet";
+import { getBlock } from "@/app/api/api";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
@@ -402,3 +403,24 @@ export async function checkArcadeBalance(
return false;
}
}
+
+export const fetchAverageBlockTime = async (
+ currentBlock: number,
+ numberOfBlocks: number
+) => {
+ try {
+ let totalTimeInterval = 0;
+
+ for (let i = currentBlock - numberOfBlocks; i < currentBlock; i++) {
+ const currentBlockData = await getBlock(i);
+ const nextBlockData = await getBlock(i + 1);
+
+ const timeInterval = nextBlockData.timestamp - currentBlockData.timestamp;
+ totalTimeInterval += timeInterval;
+ }
+ const averageTime = totalTimeInterval / numberOfBlocks;
+ return averageTime;
+ } catch (error) {
+ console.error("Error:", error);
+ }
+};
diff --git a/ui/src/app/lib/utils/parseEvents.ts b/ui/src/app/lib/utils/parseEvents.ts
index 5729826f1..6120e6fa5 100644
--- a/ui/src/app/lib/utils/parseEvents.ts
+++ b/ui/src/app/lib/utils/parseEvents.ts
@@ -236,7 +236,6 @@ export async function parseEvents(
switch (eventName) {
case "StartGame":
- console.log(raw.data);
const startGameData: StartGameEvent = {
adventurerState: parseAdventurerState(raw.data.slice(0, 40)),
adventurerMeta: {
diff --git a/ui/src/app/lib/utils/syscalls.ts b/ui/src/app/lib/utils/syscalls.ts
index bd6abc5db..db3bf0d67 100644
--- a/ui/src/app/lib/utils/syscalls.ts
+++ b/ui/src/app/lib/utils/syscalls.ts
@@ -256,13 +256,12 @@ export function syscalls({
undefined,
"StartGame"
);
- console.log(startGameEvents[0]);
const events = await parseEvents(
receipt as InvokeTransactionReceiptResponse,
{
name: formData["name"],
- startBlock: startGameEvents[0].data.startBlock,
- revealBlock: startGameEvents[0].data.revealBlock,
+ startBlock: startGameEvents[0].data[0].startBlock,
+ revealBlock: startGameEvents[0].data[0].revealBlock,
createdTime: new Date(),
}
);