Skip to content

Commit

Permalink
Merge pull request #12 from edisontim/enh/path-component
Browse files Browse the repository at this point in the history
Decouple Paths component from the EncounterTable
  • Loading branch information
edisontim authored Sep 7, 2024
2 parents e9c3a60 + 39601be commit c468099
Show file tree
Hide file tree
Showing 5 changed files with 274 additions and 168 deletions.
164 changes: 26 additions & 138 deletions ui/src/app/components/encounters/EncounterTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,41 +14,46 @@ import LootIcon from "@/app/components/icons/LootIcon";
import useAdventurerStore from "@/app/hooks/useAdventurerStore";
import { useQueriesStore } from "@/app/hooks/useQueryStore";
import useUIStore from "@/app/hooks/useUIStore";
import { AdventurerClass } from "@/app/lib/classes";
import { vitalityIncrease } from "@/app/lib/constants";
import { GameData } from "@/app/lib/data/GameData";
import { calculateLevel, getItemData, getItemPrice } from "@/app/lib/utils";
import {
getDecisionTree,
getOutcomesWithPath,
listAllEncounters,
} from "@/app/lib/utils/processFutures";
import { calculateLevel, getItemData } from "@/app/lib/utils";
import { listAllEncounters } from "@/app/lib/utils/processFutures";
import { Item } from "@/app/types";
import React, { useMemo, useState } from "react";
import { getPurchaseItemsObjects, getUpdatedAdventurer } from "./utils";
import Paths from "./Paths";

const EncounterTable = () => {
const adventurer = useAdventurerStore((state) => state.adventurer);
const adventurerEntropy = useUIStore((state) => state.adventurerEntropy);
const hasBeast = useAdventurerStore((state) => state.computed.hasBeast);

const formattedAdventurerEntropy = BigInt(adventurerEntropy);
const purchaseItems = useUIStore((state) => state.purchaseItems);
const potionAmount = useUIStore((state) => state.potionAmount);
const upgrades = useUIStore((state) => state.upgrades);

const [hoveredBeast, setHoveredBeast] = useState<number | null>(null);

const formattedAdventurerEntropy = BigInt(adventurerEntropy);

const { data } = useQueriesStore();

let gameData = new GameData();

const purchaseItemsObjects = purchaseItems
.filter((item) => item.equip)
.map((item) => {
const itemName = gameData.ITEMS[Number(item.item)];
return getItemData(itemName);
});
const upgrades = useUIStore((state) => state.upgrades);
const potionAmount = useUIStore((state) => state.potionAmount);
const purchaseItems = useUIStore((state) => state.purchaseItems);

const purchaseItemsObjects = useMemo(
() => getPurchaseItemsObjects(purchaseItems, gameData),
[purchaseItems]
);

const updatedAdventurer = useMemo(
() =>
getUpdatedAdventurer(
adventurer,
upgrades,
potionAmount,
purchaseItemsObjects
),
[adventurer, upgrades, potionAmount, purchaseItemsObjects]
);

let armoritems: Item[] =
data.itemsByAdventurerQuery?.items
Expand All @@ -64,102 +69,6 @@ const EncounterTable = () => {
return item.slot! === "Weapon";
}) || [];

const items = useMemo(() => {
let equippedItems =
data.itemsByAdventurerQuery?.items
.filter((item) => item.equipped)
.map((item) => ({
item: item.item,
...getItemData(item.item ?? ""),
special2: item.special2,
special3: item.special3,
xp: Math.max(1, item.xp!),
})) || [];

let updatedItems = equippedItems.map((item: any) => {
const purchaseItem = purchaseItemsObjects.find(
(purchaseItem) => purchaseItem.slot === item.slot
);
if (purchaseItem) {
return {
...purchaseItem,
special2: undefined,
special3: undefined,
xp: 1, // Default XP for new items
};
}
return item;
});

// Add any new items from purchaseItemsObjects that weren't replacements
purchaseItemsObjects.forEach((purchaseItem) => {
if (!updatedItems.some((item: any) => item.slot === purchaseItem.slot)) {
updatedItems.push({
...purchaseItem,
special2: undefined,
special3: undefined,
xp: 1, // Default XP for new items
});
}
});

return updatedItems;
}, [data.itemsByAdventurerQuery?.items, purchaseItemsObjects]);

const updatedAdventurer: AdventurerClass | null = useMemo(() => {
if (!adventurer) return null;

let newAdventurer: AdventurerClass = { ...adventurer };

if (upgrades.Strength > 0) {
newAdventurer.strength! += upgrades.Strength;
}
if (upgrades.Dexterity > 0) {
newAdventurer.dexterity! += upgrades.Dexterity;
}
if (upgrades.Vitality > 0) {
newAdventurer.vitality =
Number(newAdventurer.vitality) + upgrades.Vitality;
newAdventurer.health =
newAdventurer.health! + upgrades.Vitality! * vitalityIncrease;
}
if (upgrades.Intelligence > 0) {
newAdventurer.intelligence! += upgrades.Intelligence;
}
if (upgrades.Wisdom > 0) {
newAdventurer.wisdom! += upgrades.Wisdom;
}
if (upgrades.Charisma > 0) {
newAdventurer.charisma! += upgrades.Charisma;
}

// Apply purchased potions
if (potionAmount > 0) {
newAdventurer.health = Math.min(
newAdventurer.health! + potionAmount * 10,
100 + newAdventurer.vitality! * vitalityIncrease
);
}

const totalCost = purchaseItemsObjects.reduce((acc, item) => {
return acc + getItemPrice(item.tier, newAdventurer?.charisma!);
}, 0);

newAdventurer.gold = adventurer?.gold! - totalCost;

return newAdventurer;
}, [
adventurer,
potionAmount,
upgrades.Charisma,
upgrades.Intelligence,
upgrades.Strength,
upgrades.Wisdom,
upgrades.Vitality,
upgrades.Dexterity,
purchaseItemsObjects,
]);

const encounters = useMemo(
() =>
listAllEncounters(
Expand All @@ -171,21 +80,6 @@ const EncounterTable = () => {
[updatedAdventurer?.xp, formattedAdventurerEntropy]
);

const outcomesWithPath = useMemo(() => {
if (!updatedAdventurer || !items) return [];
const decisionTree = getDecisionTree(
updatedAdventurer!,
items,
formattedAdventurerEntropy,
hasBeast,
updatedAdventurer?.level!
);
return getOutcomesWithPath(decisionTree).sort(
(a, b) =>
b[b.length - 1].adventurer.health! - a[a.length - 1].adventurer.health!
);
}, [updatedAdventurer?.xp, formattedAdventurerEntropy, items]);

return (
<div className="fixed z-50">
<div className="flex flex-col gap-5 sm:gap-0 sm:flex-row justify-between w-full bg-terminal-black max-h-[300px] overflow-y-auto border border-terminal-green text-xs sm:text-base">
Expand Down Expand Up @@ -464,15 +358,9 @@ const EncounterTable = () => {
)}
</tbody>
</table>

<Paths />
</div>
<Paths
adventurerEntropy={adventurerEntropy}
updatedAdventurer={updatedAdventurer}
outcomesWithPath={outcomesWithPath}
armoritems={armoritems}
weaponItems={weaponItems}
startingLevel={adventurer?.level}
/>
</div>
</div>
</div>
Expand Down
100 changes: 81 additions & 19 deletions ui/src/app/components/encounters/Paths.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,96 @@ import {
MetalIcon,
} from "@/app/components/icons/Icons";
import LootIcon from "@/app/components/icons/LootIcon";
import { AdventurerClass } from "@/app/lib/classes";
import useAdventurerStore from "@/app/hooks/useAdventurerStore";
import { useQueriesStore } from "@/app/hooks/useQueryStore";
import useUIStore from "@/app/hooks/useUIStore";
import { GameData } from "@/app/lib/data/GameData";
import { calculateLevel } from "@/app/lib/utils";
import { calculateLevel, getItemData } from "@/app/lib/utils";
import { Step } from "@/app/lib/utils/processFutures";
import { Item } from "@/app/types";
import React, { useState } from "react";
import React, { useMemo, useState } from "react";
import {
getItems,
getPaths,
getPurchaseItemsObjects,
getUpdatedAdventurer,
} from "./utils";

type PathProps = {
adventurerEntropy: bigint;
updatedAdventurer: AdventurerClass | null;
outcomesWithPath: Step[][];
armoritems: Item[];
weaponItems: Item[];
startingLevel: number | undefined;
};
const Paths = () => {
const adventurer = useAdventurerStore((state) => state.adventurer);
const adventurerEntropy = useUIStore((state) => state.adventurerEntropy);
const hasBeast = useAdventurerStore((state) => state.computed.hasBeast);

const upgrades = useUIStore((state) => state.upgrades);
const potionAmount = useUIStore((state) => state.potionAmount);
const purchaseItems = useUIStore((state) => state.purchaseItems);

const Paths = ({
adventurerEntropy,
updatedAdventurer,
outcomesWithPath,
armoritems,
weaponItems,
startingLevel,
}: PathProps) => {
const [hoveredBeast, setHoveredBeast] = useState<number | null>(null);

const { data } = useQueriesStore();

let gameData = new GameData();

let armoritems: Item[] =
data.itemsByAdventurerQuery?.items
.map((item) => ({ ...item, ...getItemData(item.item ?? "") }))
.filter((item) => {
return !["Weapon", "Ring", "Neck"].includes(item.slot!);
}) || [];

let weaponItems: Item[] =
data.itemsByAdventurerQuery?.items
.map((item) => ({ ...item, ...getItemData(item.item ?? "") }))
.filter((item) => {
return item.slot! === "Weapon";
}) || [];

const purchaseItemsObjects = useMemo(
() => getPurchaseItemsObjects(purchaseItems, gameData),
[purchaseItems]
);

const updatedAdventurer = useMemo(
() =>
getUpdatedAdventurer(
adventurer,
upgrades,
potionAmount,
purchaseItemsObjects
),
[
adventurer,
upgrades.Charisma,
upgrades.Intelligence,
upgrades.Wisdom,
upgrades.Strength,
upgrades.Dexterity,
upgrades.Vitality,
potionAmount,
purchaseItemsObjects,
]
);

const items = useMemo(
() => getItems(purchaseItems, data, gameData),
[data.itemsByAdventurerQuery?.items, purchaseItemsObjects]
);

const outcomesWithPath = useMemo(
() =>
getPaths(
updatedAdventurer,
adventurerEntropy,
items,
gameData,
data,
hasBeast
),
[updatedAdventurer, updatedAdventurer?.xp, adventurerEntropy, items]
);

const startingLevel = adventurer?.level;

return (
<>
{updatedAdventurer?.entropy &&
Expand Down
Loading

0 comments on commit c468099

Please sign in to comment.