Compare commits
3 Commits
a45d74ebb2
...
b8f15bd31e
| Author | SHA1 | Date | |
|---|---|---|---|
| b8f15bd31e | |||
| ade655a501 | |||
| 6c1c49a0ca |
60
app/package-lock.json
generated
60
app/package-lock.json
generated
@ -14,6 +14,7 @@
|
|||||||
"next": "^14.2.10",
|
"next": "^14.2.10",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"sass": "^1.80.4",
|
||||||
"viem": "^2.17.0",
|
"viem": "^2.17.0",
|
||||||
"wagmi": "^2.12.17"
|
"wagmi": "^2.12.17"
|
||||||
},
|
},
|
||||||
@ -22,6 +23,7 @@
|
|||||||
"@types/react": "^18.3.5",
|
"@types/react": "^18.3.5",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-next": "14.2.15",
|
"eslint-config-next": "14.2.15",
|
||||||
|
"pixel-borders": "^1.1.4",
|
||||||
"typescript": "5.5.2"
|
"typescript": "5.5.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -9103,6 +9105,11 @@
|
|||||||
"node": ">=16.x"
|
"node": ">=16.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/immutable": {
|
||||||
|
"version": "4.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz",
|
||||||
|
"integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw=="
|
||||||
|
},
|
||||||
"node_modules/import-fresh": {
|
"node_modules/import-fresh": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||||
@ -12110,6 +12117,16 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/pixel-borders": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/pixel-borders/-/pixel-borders-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-jBX9MMRsCeYNl1sHnXnAgtBD5hLAMa59/MDvVBZUoeHtsF6t97goigzIPQHvssh8xsQ5w+vF7hqabutbpb0zxA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/pkg-dir": {
|
"node_modules/pkg-dir": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
|
||||||
@ -13343,6 +13360,49 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sass": {
|
||||||
|
"version": "1.80.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sass/-/sass-1.80.4.tgz",
|
||||||
|
"integrity": "sha512-rhMQ2tSF5CsuuspvC94nPM9rToiAFw2h3JTrLlgmNw1MH79v8Cr3DH6KF6o6r+8oofY3iYVPUf66KzC8yuVN1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"@parcel/watcher": "^2.4.1",
|
||||||
|
"chokidar": "^4.0.0",
|
||||||
|
"immutable": "^4.0.0",
|
||||||
|
"source-map-js": ">=0.6.2 <2.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"sass": "sass.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sass/node_modules/chokidar": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==",
|
||||||
|
"dependencies": {
|
||||||
|
"readdirp": "^4.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sass/node_modules/readdirp": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14.16.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://paulmillr.com/funding/"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/scheduler": {
|
"node_modules/scheduler": {
|
||||||
"version": "0.23.2",
|
"version": "0.23.2",
|
||||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"next": "^14.2.10",
|
"next": "^14.2.10",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"sass": "^1.80.4",
|
||||||
"viem": "^2.17.0",
|
"viem": "^2.17.0",
|
||||||
"wagmi": "^2.12.17"
|
"wagmi": "^2.12.17"
|
||||||
},
|
},
|
||||||
@ -23,6 +24,7 @@
|
|||||||
"@types/react": "^18.3.5",
|
"@types/react": "^18.3.5",
|
||||||
"eslint": "8.57.0",
|
"eslint": "8.57.0",
|
||||||
"eslint-config-next": "14.2.15",
|
"eslint-config-next": "14.2.15",
|
||||||
|
"pixel-borders": "^1.1.4",
|
||||||
"typescript": "5.5.2"
|
"typescript": "5.5.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { UnitType, usePlayer } from '../providers/PlayerProvider';
|
import { UnitType, usePlayer } from "../providers/PlayerProvider";
|
||||||
import styles from '../styles/Army.module.css';
|
import styles from "../styles/Army.module.css";
|
||||||
import { calculateBalance, toReadable } from './Counter';
|
import { calculateBalance, toReadable } from "./Counter";
|
||||||
|
import PixelatedQuote from "./PixelatedQuote";
|
||||||
|
|
||||||
const PRECISION = BigInt(10000);
|
const PRECISION = BigInt(10000);
|
||||||
const PRICE_FACTOR = BigInt(11500);
|
const PRICE_FACTOR = BigInt(11500);
|
||||||
@ -11,16 +12,20 @@ const base_cost: Record<UnitType, bigint> = {
|
|||||||
1: BigInt(3420000),
|
1: BigInt(3420000),
|
||||||
2: BigInt(30096000),
|
2: BigInt(30096000),
|
||||||
3: BigInt(255816000),
|
3: BigInt(255816000),
|
||||||
}
|
};
|
||||||
|
|
||||||
const profits: Record<UnitType, bigint> = {
|
const profits: Record<UnitType, bigint> = {
|
||||||
0: BigInt(2533),
|
0: BigInt(2533),
|
||||||
1: BigInt(27863),
|
1: BigInt(27863),
|
||||||
2: BigInt(306493),
|
2: BigInt(306493),
|
||||||
3: BigInt(3371423),
|
3: BigInt(3371423),
|
||||||
}
|
};
|
||||||
|
|
||||||
function calculateUnitPrice(unit: UnitType, currentLevel: number, units: number) {
|
function calculateUnitPrice(
|
||||||
|
unit: UnitType,
|
||||||
|
currentLevel: number,
|
||||||
|
units: number
|
||||||
|
) {
|
||||||
let rollingPriceCalculation = base_cost[unit];
|
let rollingPriceCalculation = base_cost[unit];
|
||||||
let price = BigInt(0);
|
let price = BigInt(0);
|
||||||
|
|
||||||
@ -29,127 +34,171 @@ function calculateUnitPrice(unit: UnitType, currentLevel: number, units: number)
|
|||||||
if (i >= currentLevel) {
|
if (i >= currentLevel) {
|
||||||
price += rollingPriceCalculation;
|
price += rollingPriceCalculation;
|
||||||
}
|
}
|
||||||
rollingPriceCalculation = rollingPriceCalculation * PRICE_FACTOR / PRECISION;
|
rollingPriceCalculation =
|
||||||
|
(rollingPriceCalculation * PRICE_FACTOR) / PRECISION;
|
||||||
}
|
}
|
||||||
return price;
|
return price;
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateProfitPerSecond(unit: UnitType, level: number) {
|
function calculateProfitPerSecond(unit: UnitType, level: number) {
|
||||||
// Each next unit scales progressivelly better
|
// Each next unit scales progressivelly better
|
||||||
return BigInt(level) * profits[unit]
|
return BigInt(level) * profits[unit];
|
||||||
}
|
}
|
||||||
|
|
||||||
const unitTypeToCss: Record<UnitType, string> = {
|
const unitTypeToCss: Record<UnitType, string> = {
|
||||||
0: styles.moloch_denier,
|
0: styles.moloch_denier,
|
||||||
1: styles.apprentice,
|
1: styles.apprentice,
|
||||||
2: styles.anointed,
|
2: styles.anointed,
|
||||||
3: styles.champion
|
3: styles.champion,
|
||||||
}
|
};
|
||||||
|
|
||||||
const unitTypeToName: Record<UnitType, string> = {
|
const unitTypeToName: Record<UnitType, string> = {
|
||||||
0: "Moloch denier",
|
0: "Moloch denier",
|
||||||
1: "Apprentice",
|
1: "Apprentice",
|
||||||
2: "Anointed",
|
2: "Anointed",
|
||||||
3: "Champion"
|
3: "Champion",
|
||||||
}
|
};
|
||||||
|
|
||||||
const defaultAvailabilityMap: Record<UnitType, boolean> = {
|
const defaultAvailabilityMap: Record<UnitType, boolean> = {
|
||||||
0: false,
|
0: false,
|
||||||
1: false,
|
1: false,
|
||||||
2: false,
|
2: false,
|
||||||
3: false
|
3: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
const unitDiscoveredAt: Record<UnitType, bigint> = {
|
const unitDiscoveredAt: Record<UnitType, bigint> = {
|
||||||
0: BigInt(0),
|
0: BigInt(0),
|
||||||
1: BigInt(300_0000),
|
1: BigInt(300_0000),
|
||||||
2: BigInt(2800_0000),
|
2: BigInt(2800_0000),
|
||||||
3: BigInt(24000_0000)
|
3: BigInt(24000_0000),
|
||||||
}
|
};
|
||||||
const unitAvailableToDiscoverAt: Record<UnitType, bigint> = {
|
const unitAvailableToDiscoverAt: Record<UnitType, bigint> = {
|
||||||
0: BigInt(0),
|
0: BigInt(0),
|
||||||
1: BigInt(200_0000),
|
1: BigInt(200_0000),
|
||||||
2: BigInt(2000_0000),
|
2: BigInt(2000_0000),
|
||||||
3: BigInt(25000_0000),
|
3: BigInt(25000_0000),
|
||||||
}
|
};
|
||||||
|
|
||||||
interface UnitProps {
|
interface UnitProps {
|
||||||
addUnit: (unitType: UnitType) => void;
|
addUnit: (unitType: UnitType) => void;
|
||||||
unitType: UnitType;
|
unitType: UnitType;
|
||||||
canPurchase: boolean;
|
canPurchase: boolean;
|
||||||
isShrouded: boolean;
|
isShrouded: boolean;
|
||||||
n_units: number
|
n_units: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Unit = ({ addUnit, unitType, canPurchase, isShrouded, n_units }: UnitProps) => {
|
const Unit = ({
|
||||||
|
addUnit,
|
||||||
|
unitType,
|
||||||
|
canPurchase,
|
||||||
|
isShrouded,
|
||||||
|
n_units,
|
||||||
|
}: UnitProps) => {
|
||||||
const [unitPrice, unitProfit] = useMemo(() => {
|
const [unitPrice, unitProfit] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
toReadable(calculateUnitPrice(unitType, n_units, 1)),
|
toReadable(calculateUnitPrice(unitType, n_units, 1)),
|
||||||
toReadable(calculateProfitPerSecond(unitType, n_units))
|
toReadable(calculateProfitPerSecond(unitType, n_units)),
|
||||||
]
|
];
|
||||||
}, [n_units, unitType]);
|
}, [n_units, unitType]);
|
||||||
return <div onClick={() => addUnit(unitType)} className={`${styles.armyUnit} ${canPurchase ? "" : styles.isUnavailable}`}>
|
return (
|
||||||
<div className={`
|
<div
|
||||||
|
onClick={() => addUnit(unitType)}
|
||||||
|
className={`${styles.armyUnit} ${canPurchase ? "" : styles.isUnavailable
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className={`
|
||||||
${unitTypeToCss[unitType]}
|
${unitTypeToCss[unitType]}
|
||||||
${styles.person}
|
${styles.person}
|
||||||
${styles.static}
|
${styles.static}
|
||||||
${isShrouded ? styles.isShrouded : ""}
|
${isShrouded ? styles.isShrouded : ""}
|
||||||
`} />
|
`}
|
||||||
<span className={`${styles.unitName} ${styles.uiElement}`}>{isShrouded ? "???????" : unitTypeToName[unitType]}</span>
|
/>
|
||||||
{isShrouded ? null : <span className={`${styles.unitPrice} ${styles.uiElement}`}>{unitPrice} <small>GELD</small></span>}
|
<span className={`${styles.unitName} ${styles.uiElement}`}>
|
||||||
{n_units > 0 ? <span className={`${styles.unitSupply} ${styles.uiElement}`}>{n_units}</span> : null}
|
{isShrouded ? "???????" : unitTypeToName[unitType]}
|
||||||
{n_units > 0 ? <span className={`${styles.unitProfit} ${styles.uiElement}`}>{unitProfit} <small>per sec</small></span> : null}
|
</span>
|
||||||
|
{isShrouded ? null : (
|
||||||
|
<span className={`${styles.unitPrice} ${styles.uiElement}`}>
|
||||||
|
{unitPrice} <small>GELD</small>
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{n_units > 0 ? (
|
||||||
|
<span className={`${styles.unitSupply} ${styles.uiElement}`}>
|
||||||
|
{n_units}
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
{n_units > 0 ? (
|
||||||
|
<span className={`${styles.unitProfit} ${styles.uiElement}`}>
|
||||||
|
{unitProfit} <small>per sec</small>
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const Army = () => {
|
const Army = () => {
|
||||||
const { army, addUnit, isRegistered, player, balance } = usePlayer()
|
const { army, addUnit, isRegistered, player, balance } = usePlayer();
|
||||||
const [canPurchase, setCanPurchase] = useState<Record<UnitType, boolean>>(defaultAvailabilityMap);
|
const [canPurchase, setCanPurchase] = useState<Record<UnitType, boolean>>(
|
||||||
const [isShrouded, setIsShrouded] = useState<Record<UnitType, boolean>>(defaultAvailabilityMap);
|
defaultAvailabilityMap
|
||||||
const [canKnowAbout, setCanKnowAbout] = useState<Record<UnitType, boolean>>(defaultAvailabilityMap);
|
);
|
||||||
const balanceCount = useRef(BigInt(balance ?? 0))
|
const [isShrouded, setIsShrouded] = useState<Record<UnitType, boolean>>(
|
||||||
|
defaultAvailabilityMap
|
||||||
|
);
|
||||||
|
const [canKnowAbout, setCanKnowAbout] = useState<Record<UnitType, boolean>>(
|
||||||
|
defaultAvailabilityMap
|
||||||
|
);
|
||||||
|
const balanceCount = useRef(BigInt(balance ?? 0));
|
||||||
|
|
||||||
const setAvailabilities = useCallback(() => {
|
const setAvailabilities = useCallback(() => {
|
||||||
if (isRegistered) {
|
if (isRegistered) {
|
||||||
const totalMinted = (player?.total_minted ?? BigInt(0)) + (balanceCount.current - (balance ?? BigInt(0)));
|
const totalMinted =
|
||||||
|
(player?.total_minted ?? BigInt(0)) +
|
||||||
|
(balanceCount.current - (balance ?? BigInt(0)));
|
||||||
const n_units: Record<UnitType, number> = {
|
const n_units: Record<UnitType, number> = {
|
||||||
0: army?.moloch_denier.level ?? 0,
|
0: army?.moloch_denier.level ?? 0,
|
||||||
1: army?.apprentice.level ?? 0,
|
1: army?.apprentice.level ?? 0,
|
||||||
2: army?.anointed.level ?? 0,
|
2: army?.anointed.level ?? 0,
|
||||||
3: army?.champion.level ?? 0,
|
3: army?.champion.level ?? 0,
|
||||||
}
|
};
|
||||||
const inShroud = {
|
const inShroud = {
|
||||||
0: totalMinted < unitDiscoveredAt[0],
|
0: totalMinted < unitDiscoveredAt[0],
|
||||||
1: totalMinted < unitDiscoveredAt[1],
|
1: totalMinted < unitDiscoveredAt[1],
|
||||||
2: totalMinted < unitDiscoveredAt[2],
|
2: totalMinted < unitDiscoveredAt[2],
|
||||||
3: totalMinted < unitDiscoveredAt[3],
|
3: totalMinted < unitDiscoveredAt[3],
|
||||||
}
|
};
|
||||||
const isKnown = {
|
const isKnown = {
|
||||||
0: totalMinted >= unitAvailableToDiscoverAt[0],
|
0: totalMinted >= unitAvailableToDiscoverAt[0],
|
||||||
1: totalMinted >= unitAvailableToDiscoverAt[1],
|
1: totalMinted >= unitAvailableToDiscoverAt[1],
|
||||||
2: totalMinted >= unitAvailableToDiscoverAt[2],
|
2: totalMinted >= unitAvailableToDiscoverAt[2],
|
||||||
3: totalMinted >= unitAvailableToDiscoverAt[3],
|
3: totalMinted >= unitAvailableToDiscoverAt[3],
|
||||||
}
|
|
||||||
const canActuallyBuy = {
|
|
||||||
0: balanceCount.current >= calculateUnitPrice(0, n_units[0], 1) && isKnown[0] && !inShroud[0],
|
|
||||||
1: balanceCount.current >= calculateUnitPrice(1, n_units[1], 1) && isKnown[1] && !inShroud[1],
|
|
||||||
2: balanceCount.current >= calculateUnitPrice(2, n_units[2], 1) && isKnown[2] && !inShroud[2],
|
|
||||||
3: balanceCount.current >= calculateUnitPrice(3, n_units[3], 1) && isKnown[3] && !inShroud[3],
|
|
||||||
};
|
};
|
||||||
setCanPurchase(canActuallyBuy)
|
const canActuallyBuy = {
|
||||||
setIsShrouded(inShroud)
|
0:
|
||||||
setCanKnowAbout(isKnown)
|
balanceCount.current >= calculateUnitPrice(0, n_units[0], 1) &&
|
||||||
|
isKnown[0] &&
|
||||||
|
!inShroud[0],
|
||||||
|
1:
|
||||||
|
balanceCount.current >= calculateUnitPrice(1, n_units[1], 1) &&
|
||||||
|
isKnown[1] &&
|
||||||
|
!inShroud[1],
|
||||||
|
2:
|
||||||
|
balanceCount.current >= calculateUnitPrice(2, n_units[2], 1) &&
|
||||||
|
isKnown[2] &&
|
||||||
|
!inShroud[2],
|
||||||
|
3:
|
||||||
|
balanceCount.current >= calculateUnitPrice(3, n_units[3], 1) &&
|
||||||
|
isKnown[3] &&
|
||||||
|
!inShroud[3],
|
||||||
|
};
|
||||||
|
setCanPurchase(canActuallyBuy);
|
||||||
|
setIsShrouded(inShroud);
|
||||||
|
setCanKnowAbout(isKnown);
|
||||||
} else {
|
} else {
|
||||||
setCanPurchase(defaultAvailabilityMap)
|
setCanPurchase(defaultAvailabilityMap);
|
||||||
setIsShrouded(defaultAvailabilityMap)
|
setIsShrouded(defaultAvailabilityMap);
|
||||||
setCanKnowAbout(defaultAvailabilityMap)
|
setCanKnowAbout(defaultAvailabilityMap);
|
||||||
}
|
}
|
||||||
}, [
|
}, [army, balance, isRegistered, player?.total_minted]);
|
||||||
army,
|
|
||||||
balance,
|
|
||||||
isRegistered,
|
|
||||||
player?.total_minted
|
|
||||||
])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const tickInterval = setInterval(() => {
|
const tickInterval = setInterval(() => {
|
||||||
@ -158,20 +207,63 @@ const Army = () => {
|
|||||||
army?.profit_per_second ?? BigInt(0),
|
army?.profit_per_second ?? BigInt(0),
|
||||||
player?.last_raided_at ?? BigInt(0)
|
player?.last_raided_at ?? BigInt(0)
|
||||||
);
|
);
|
||||||
setAvailabilities()
|
setAvailabilities();
|
||||||
}, 100);
|
}, 100);
|
||||||
return () => clearInterval(tickInterval)
|
return () => clearInterval(tickInterval);
|
||||||
}, [balance, army?.profit_per_second, player?.last_raided_at, setAvailabilities])
|
}, [
|
||||||
|
balance,
|
||||||
|
army?.profit_per_second,
|
||||||
|
player?.last_raided_at,
|
||||||
|
setAvailabilities,
|
||||||
|
]);
|
||||||
|
|
||||||
return <>
|
return (
|
||||||
<div className={`${styles.tavern_keeper} ${styles.person} ${styles.static}`} />
|
<>
|
||||||
|
<div
|
||||||
|
className={`${styles.tavern_keeper} ${styles.person} ${styles.static}`}
|
||||||
|
>
|
||||||
|
<PixelatedQuote />
|
||||||
|
</div>
|
||||||
<div className={styles.armyUnits}>
|
<div className={styles.armyUnits}>
|
||||||
{canKnowAbout[0] && <Unit n_units={army?.moloch_denier.level ?? 0} addUnit={addUnit} unitType={0} canPurchase={canPurchase[0]} isShrouded={isShrouded[0]} />}
|
{canKnowAbout[0] && (
|
||||||
{canKnowAbout[1] && <Unit n_units={army?.apprentice.level ?? 0} addUnit={addUnit} unitType={1} canPurchase={canPurchase[1]} isShrouded={isShrouded[1]} />}
|
<Unit
|
||||||
{canKnowAbout[2] && <Unit n_units={army?.anointed.level ?? 0} addUnit={addUnit} unitType={2} canPurchase={canPurchase[2]} isShrouded={isShrouded[2]} />}
|
n_units={army?.moloch_denier.level ?? 0}
|
||||||
{canKnowAbout[3] && <Unit n_units={army?.champion.level ?? 0} addUnit={addUnit} unitType={3} canPurchase={canPurchase[3]} isShrouded={isShrouded[3]} />}
|
addUnit={addUnit}
|
||||||
|
unitType={0}
|
||||||
|
canPurchase={canPurchase[0]}
|
||||||
|
isShrouded={isShrouded[0]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{canKnowAbout[1] && (
|
||||||
|
<Unit
|
||||||
|
n_units={army?.apprentice.level ?? 0}
|
||||||
|
addUnit={addUnit}
|
||||||
|
unitType={1}
|
||||||
|
canPurchase={canPurchase[1]}
|
||||||
|
isShrouded={isShrouded[1]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{canKnowAbout[2] && (
|
||||||
|
<Unit
|
||||||
|
n_units={army?.anointed.level ?? 0}
|
||||||
|
addUnit={addUnit}
|
||||||
|
unitType={2}
|
||||||
|
canPurchase={canPurchase[2]}
|
||||||
|
isShrouded={isShrouded[2]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{canKnowAbout[3] && (
|
||||||
|
<Unit
|
||||||
|
n_units={army?.champion.level ?? 0}
|
||||||
|
addUnit={addUnit}
|
||||||
|
unitType={3}
|
||||||
|
canPurchase={canPurchase[3]}
|
||||||
|
isShrouded={isShrouded[3]}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default Army
|
export default Army;
|
||||||
|
|||||||
56
app/src/components/PixelatedQuote.tsx
Normal file
56
app/src/components/PixelatedQuote.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { useState, useEffect, useRef } from "react";
|
||||||
|
import styles from "../styles/Army.module.css"
|
||||||
|
|
||||||
|
const tavernerQuotes = [
|
||||||
|
"There is always Moloch to be slain here...",
|
||||||
|
"We prioritize Shipping at All Costs!",
|
||||||
|
"Get out there RAIDER, Moloch won't Slay Himself!",
|
||||||
|
];
|
||||||
|
|
||||||
|
function PixelatedQuote() {
|
||||||
|
const [isShown, setIsShown] = useState(true);
|
||||||
|
const [currentQuote, setCurrentQuote] = useState(
|
||||||
|
"Welcome to the Dark Forest!"
|
||||||
|
);
|
||||||
|
const intervalIdRef = useRef<NodeJS.Timeout | null>(null); // Define the type for Node environment compatibility
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (intervalIdRef.current !== null) {
|
||||||
|
clearInterval(intervalIdRef.current);
|
||||||
|
} // Clear interval if it exists
|
||||||
|
|
||||||
|
// Set up an interval to show the toast every 10 seconds
|
||||||
|
intervalIdRef.current = setInterval(() => {
|
||||||
|
setCurrentQuote(
|
||||||
|
tavernerQuotes[Math.floor(Math.random() * tavernerQuotes.length)]
|
||||||
|
);
|
||||||
|
setIsShown(true);
|
||||||
|
|
||||||
|
// Hide the toast after 4 seconds
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsShown(false);
|
||||||
|
}, 4000);
|
||||||
|
}, 6000);
|
||||||
|
|
||||||
|
// Clean up the interval on component unmount
|
||||||
|
return () => {
|
||||||
|
if (intervalIdRef.current !== null) {
|
||||||
|
clearInterval(intervalIdRef.current); // Clear interval using correct reference
|
||||||
|
intervalIdRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
className={`pixel-borders pixel-borders--2 pixelFont ${styles.pixelQuote}`}
|
||||||
|
style={{ opacity: isShown ? 1 : 0 /* Control visibility with opacity */ }}
|
||||||
|
>
|
||||||
|
{currentQuote}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PixelatedQuote;
|
||||||
@ -1,15 +1,19 @@
|
|||||||
import '../styles/globals.css';
|
import "../styles/globals.css";
|
||||||
import '@rainbow-me/rainbowkit/styles.css';
|
import "../styles/pixelatedBorders.scss";
|
||||||
import type { AppProps } from 'next/app';
|
import "@rainbow-me/rainbowkit/styles.css";
|
||||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
import type { AppProps } from "next/app";
|
||||||
import { WagmiProvider } from 'wagmi';
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
import { RainbowKitProvider, midnightTheme } from '@rainbow-me/rainbowkit';
|
import { WagmiProvider } from "wagmi";
|
||||||
import { config } from '../wagmi';
|
import { RainbowKitProvider, midnightTheme } from "@rainbow-me/rainbowkit";
|
||||||
import { Texturina } from 'next/font/google'
|
import { config } from "../wagmi";
|
||||||
import PlayerProvider from '../providers/PlayerProvider';
|
import { Press_Start_2P, Texturina } from "next/font/google";
|
||||||
|
import PlayerProvider from "../providers/PlayerProvider";
|
||||||
|
|
||||||
const client = new QueryClient();
|
const client = new QueryClient();
|
||||||
const font = Texturina({ weight: ['400'], subsets: ["latin"] })
|
const font = Texturina({ weight: ["400"], subsets: ["latin"] });
|
||||||
|
|
||||||
|
// Tavern keeper quote
|
||||||
|
const fontPixel = Press_Start_2P({ weight: ["400"], subsets: ["latin"] });
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
return (
|
return (
|
||||||
@ -17,12 +21,25 @@ function MyApp({ Component, pageProps }: AppProps) {
|
|||||||
<QueryClientProvider client={client}>
|
<QueryClientProvider client={client}>
|
||||||
<RainbowKitProvider theme={midnightTheme()}>
|
<RainbowKitProvider theme={midnightTheme()}>
|
||||||
<style jsx global>{`
|
<style jsx global>{`
|
||||||
html, body, p, span, a {
|
html,
|
||||||
|
body,
|
||||||
|
p,
|
||||||
|
span,
|
||||||
|
a {
|
||||||
font-family: ${font.style.fontFamily};
|
font-family: ${font.style.fontFamily};
|
||||||
}
|
}
|
||||||
h1, h2, h3, h4, h5, h6, .title {
|
h1,
|
||||||
|
h2,
|
||||||
|
h3,
|
||||||
|
h4,
|
||||||
|
h5,
|
||||||
|
h6,
|
||||||
|
.title {
|
||||||
font-family: ${font.style.fontFamily};
|
font-family: ${font.style.fontFamily};
|
||||||
}
|
}
|
||||||
|
.pixelFont {
|
||||||
|
font-family: ${fontPixel.style.fontFamily};
|
||||||
|
}
|
||||||
`}</style>
|
`}</style>
|
||||||
<PlayerProvider>
|
<PlayerProvider>
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
|
|||||||
@ -199,6 +199,20 @@
|
|||||||
bottom: 160px;
|
bottom: 160px;
|
||||||
width: 90px;
|
width: 90px;
|
||||||
height: 90px;
|
height: 90px;
|
||||||
|
|
||||||
|
.pixelQuote {
|
||||||
|
min-width: 150px;
|
||||||
|
color: black;
|
||||||
|
font-size: 0.7rem;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 5.5rem;
|
||||||
|
left: -20px;
|
||||||
|
right: 0;
|
||||||
|
padding: 0.7rem;
|
||||||
|
line-height: 0.8rem;
|
||||||
|
transition: opacity 1s ease-in-out;
|
||||||
|
box-shadow: 0px 5px 10px 5px rgba(0, 0, 0, 0.4);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.static.moloch_denier {
|
.static.moloch_denier {
|
||||||
background-image: url("/roles/scribe2.png");
|
background-image: url("/roles/scribe2.png");
|
||||||
|
|||||||
3
app/src/styles/pixelatedBorders.scss
Normal file
3
app/src/styles/pixelatedBorders.scss
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
@import "../../node_modules/pixel-borders/src/styles/pixel-borders.scss";
|
||||||
|
@import "../../node_modules/pixel-borders/src/styles/pixel-borders/pixel-borders-mixins";
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user