Skip to content

Commit

Permalink
🎨 Initial fixes for AI solution. Still WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
MathiasGruber committed Feb 20, 2025
1 parent 0bb5c84 commit 7e8db24
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 3 deletions.
9 changes: 9 additions & 0 deletions app/drizzle/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,15 @@ export const COST_REROLL_ELEMENT = 20;
export const MAX_EXTRA_JUTSU_SLOTS = 2;
export const BLOODLINE_ROLL_TYPES = ["NATURAL", "ITEM"] as const;

// Jutsu level transfer config
export const JUTSU_TRANSFER_DAYS = 20;
export const JUTSU_TRANSFER_COST = 20;
export const JUTSU_TRANSFER_MAX_LEVEL = 20;
export const JUTSU_TRANSFER_FREE_AMOUNT = 2;
export const JUTSU_TRANSFER_FREE_NORMAL = 3;
export const JUTSU_TRANSFER_FREE_SILVER = 4;
export const JUTSU_TRANSFER_FREE_GOLD = 5;

// Village config
export const VILLAGE_LEAVE_REQUIRED_RANK = "CHUNIN";
export const VILLAGE_REDUCED_GAINS_DAYS = 7;
Expand Down
104 changes: 102 additions & 2 deletions app/src/app/jutsus/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useState } from "react";
import { Trash2, CircleFadingArrowUp } from "lucide-react";
import { Trash2, CircleFadingArrowUp, ArrowRightLeft } from "lucide-react";
import ItemWithEffects from "@/layout/ItemWithEffects";
import ContentBox from "@/layout/ContentBox";
import Modal from "@/layout/Modal";
Expand Down Expand Up @@ -29,8 +29,19 @@ import { showMutationToast } from "@/libs/toast";
import { JUTSU_XP_TO_LEVEL } from "@/drizzle/constants";
import { COST_EXTRA_JUTSU_SLOT } from "@/drizzle/constants";
import { MAX_EXTRA_JUTSU_SLOTS } from "@/drizzle/constants";
import { JUTSU_TRANSFER_COST } from "@/drizzle/constants";
import { JUTSU_TRANSFER_MAX_LEVEL } from "@/drizzle/constants";
import { JUTSU_TRANSFER_DAYS } from "@/drizzle/constants";
import {
JUTSU_TRANSFER_FREE_GOLD,
JUTSU_TRANSFER_FREE_SILVER,
JUTSU_TRANSFER_FREE_NORMAL,
JUTSU_TRANSFER_FREE_AMOUNT,
} from "@/drizzle/constants";
import { getFreeTransfers } from "@/libs/jutsu";
import JutsuFiltering, { useFiltering, getFilter } from "@/layout/JutsuFiltering";
import type { Jutsu, UserJutsu } from "@/drizzle/schema";
import type { RouterOutputs } from "@/app/_trpc/client";

export default function MyJutsu() {
// tRPC utility
Expand All @@ -46,6 +57,9 @@ export default function MyJutsu() {
const [userjutsu, setUserJutsu] = useState<(Jutsu & UserJutsu) | undefined>(
undefined,
);
const [transferTarget, setTransferTarget] = useState<(Jutsu & UserJutsu) | undefined>(
undefined,
);

// User Jutsus & items
const { data: userJutsus, isFetching: l1 } = api.jutsu.getUserJutsus.useQuery(
Expand All @@ -71,6 +85,7 @@ export default function MyJutsu() {
document.body.style.cursor = "default";
setIsOpen(false);
setUserJutsu(undefined);
setTransferTarget(undefined);
};

// Mutations
Expand Down Expand Up @@ -133,7 +148,19 @@ export default function MyJutsu() {
},
});

const isPending = isToggling || isForgetting || isUpgrading || isUnequipping;
const { mutate: transferLevel, isPending: isTransferring } =
api.jutsu.transferLevel.useMutation({
onSuccess: async (data) => {
showMutationToast(data);
if (data.success) {
await utils.jutsu.getUserJutsus.invalidate();
}
},
onSettled,
});

const isPending =
isToggling || isForgetting || isUpgrading || isUnequipping || isTransferring;
const isFetching = l1 || l2;

// Collapse UserItem and Item
Expand Down Expand Up @@ -195,6 +222,15 @@ export default function MyJutsu() {
// Ryo from forgetting
const forgetRyo = 0;

// Transfer costs
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - JUTSU_TRANSFER_DAYS);
const { data: recentTransfers } = api.jutsu.getRecentTransfers.useQuery<
RouterOutputs["jutsu"]["getRecentTransfers"]
>({ cutoffDate }, { enabled: !!userData });
const freeTransfers = getFreeTransfers(userData?.federalStatus || "NONE");
const usedTransfers = recentTransfers?.length || 0;

// Loaders
if (!userData) return <Loader explanation="Loading userdata" />;

Expand Down Expand Up @@ -325,6 +361,70 @@ export default function MyJutsu() {
)}

<div className="grow"></div>
{userjutsu.level <= JUTSU_TRANSFER_MAX_LEVEL && (
<Confirm
title="Transfer Level"
button={
<Button id="transfer" variant="secondary">
<ArrowRightLeft className="h-6 w-6 mr-2" />
Transfer Level
</Button>
}
proceed_label={
transferTarget ? "Confirm Transfer" : "Select Target"
}
onAccept={(e) => {
e.preventDefault();
if (transferTarget) {
transferLevel({
fromJutsuId: userjutsu.jutsuId,
toJutsuId: transferTarget.jutsuId,
});
} else {
setIsOpen(false);
const filteredJutsus = allJutsu?.filter(
(j) =>
j.jutsuId !== userjutsu.jutsuId &&
j.jutsuType === userjutsu.jutsuType &&
j.jutsuRank === userjutsu.jutsuRank,
);
if (filteredJutsus?.length) {
setTransferTarget(undefined);
setUserJutsu(userjutsu);
const targetJutsu = filteredJutsus[0];
setTransferTarget(targetJutsu);
setIsOpen(true);
} else {
showMutationToast({
success: false,
message: "No compatible jutsu found for transfer",
});
}
}
}}
>
{transferTarget ? (
<>
<p>
Transfer level {userjutsu.level} from {userjutsu.name} to{" "}
{transferTarget.name}?
</p>
<p>
This will reset {userjutsu.name} to level 1 and set{" "}
{transferTarget.name} to level {userjutsu.level}.
</p>
<p>
Cost:{" "}
{usedTransfers >= freeTransfers
? `${JUTSU_TRANSFER_COST} reputation points`
: "Free"}
</p>
</>
) : (
<p>Select a jutsu to transfer the level to.</p>
)}
</Confirm>
)}
<Confirm
title="Forget Jutsu"
button={
Expand Down
17 changes: 17 additions & 0 deletions app/src/layout/JutsuFiltering.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ export const useFiltering = () => {
const [classification, setClassification] = useState<StatType | None>("None");
const [effect, setEffect] = useState<string[]>([]);
const [element, setElement] = useState<string[]>([]);
const [jutsuType, setJutsuType] = useState<string>("None");
const [method, setMethod] = useState<AttackMethod | None>("None");
const [name, setName] = useState<string>("");
const [rank, setRank] = useState<UserRank>("NONE");
Expand Down Expand Up @@ -233,6 +234,7 @@ export const useFiltering = () => {
effect,
element,
hidden,
jutsuType,
method,
name,
rank,
Expand Down Expand Up @@ -262,6 +264,7 @@ export const useFiltering = () => {
setEffect,
setElement,
setHidden,
setJutsuType,
setMethod,
setName,
setRank,
Expand Down Expand Up @@ -305,6 +308,7 @@ const JutsuFiltering: React.FC<JutsuFilteringProps> = (props) => {
effect,
element,
hidden,
jutsuType,
method,
name,
rank,
Expand Down Expand Up @@ -334,6 +338,7 @@ const JutsuFiltering: React.FC<JutsuFilteringProps> = (props) => {
setEffect,
setElement,
setHidden,
setJutsuType,
setMethod,
setName,
setRank,
Expand Down Expand Up @@ -646,6 +651,17 @@ const JutsuFiltering: React.FC<JutsuFilteringProps> = (props) => {
}))}
/>

{/* Jutsu Type */}
<FilterSelect
label="Jutsu Type"
value={jutsuType}
onValueChange={setJutsuType}
options={JutsuTypes.map((type) => ({
value: type,
label: type,
}))}
/>

{/* Target */}
<FilterSelect
label="Target"
Expand Down Expand Up @@ -854,6 +870,7 @@ export const getFilter = (state: JutsuFilteringState) => {
disappear: state.removeAnim === "None" ? undefined : state.removeAnim,
effect: processArray(state.effect as EffectType[]),
element: processArray(state.element as ElementName[]),
jutsuType: state.jutsuType === "None" ? undefined : state.jutsuType,
method: state.method === "None" ? undefined : state.method,
name: state.name || undefined,
rank: state.rank === "NONE" ? undefined : state.rank,
Expand Down
23 changes: 23 additions & 0 deletions app/src/libs/jutsu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import { JutsuTypes } from "@/drizzle/constants";
import { UserRanks } from "@/drizzle/constants";
import { StatTypes } from "@/drizzle/constants";
import { showMutationToast, showFormErrorsToast } from "@/libs/toast";
import { JUTSU_TRANSFER_FREE_AMOUNT } from "@/drizzle/constants";
import { JUTSU_TRANSFER_FREE_NORMAL } from "@/drizzle/constants";
import { JUTSU_TRANSFER_FREE_SILVER } from "@/drizzle/constants";
import { JUTSU_TRANSFER_FREE_GOLD } from "@/drizzle/constants";
import type { FederalStatus } from "@/drizzle/constants";
import type { ZodAllTags } from "@/libs/combat/types";
import type { ZodJutsuType } from "@/libs/combat/types";
import type { FormEntry } from "@/layout/EditContent";
Expand Down Expand Up @@ -103,3 +108,21 @@ export const useJutsuEditForm = (data: Jutsu, refetch: () => void) => {

return { jutsu, effects, form, formData, loading, setEffects, handleJutsuSubmit };
};

/**
* Get the number of free jutsu level transfers based on the federal status
* @param federalStatus
* @returns
*/
export const getFreeTransfers = (federalStatus: FederalStatus) => {
switch (federalStatus) {
case "GOLD":
return JUTSU_TRANSFER_FREE_GOLD;
case "SILVER":
return JUTSU_TRANSFER_FREE_SILVER;
case "NORMAL":
return JUTSU_TRANSFER_FREE_NORMAL;
default:
return JUTSU_TRANSFER_FREE_AMOUNT;
}
};
Loading

0 comments on commit 7e8db24

Please sign in to comment.