New source found from dndbeyond.com

This commit is contained in:
2026-07-08 01:00:09 -07:00
parent 9a983a6d7b
commit dcefa0d2f2
2865 changed files with 222467 additions and 49053 deletions
@@ -0,0 +1,267 @@
import { FC, HTMLAttributes, useEffect, useState } from "react";
import {
ShortModelInfoContract,
ApiRequests,
serviceDataActions,
} from "@dndbeyond/character-rules-engine/es";
import { Checkbox } from "~/components/Checkbox";
import { RadioGroup } from "~/components/RadioGroup";
import { PreferenceLongRestTypeEnum } from "~/constants";
import { useCharacterEngine } from "~/hooks/useCharacterEngine";
import { useDispatch } from "~/hooks/useDispatch";
import { Header } from "~/subApps/sheet/components/Sidebar/components/Header";
import { toastMessageActions } from "~/tools/js/Shared/actions";
import ThemeButton from "~/tools/js/Shared/components/common/Button/ThemeButton/ThemeButton";
import DataLoadingStatusEnum from "~/tools/js/Shared/constants/DataLoadingStatusEnum";
import { AppLoggerUtils } from "~/tools/js/Shared/utils";
import { RestoreLifeManager } from "../HitPointsManagePane/RestoreLifeManager";
import styles from "./styles.module.css";
interface LongRestPaneProps extends HTMLAttributes<HTMLDivElement> {}
export const LongRestPane: FC<LongRestPaneProps> = ({ ...props }) => {
const [resetMaxHpModifier, setResetMaxHpModifier] = useState(true);
const [adjustConditionLevel, setAdjustConditionLevel] = useState(false);
const [restMessageLoadingStatus, setRestMessageLoadingStatus] =
useState<DataLoadingStatusEnum>(DataLoadingStatusEnum.NOT_INITIALIZED);
const {
activeConditions,
isDead,
preferences,
characterUtils,
helperUtils,
apiAdapterUtils,
characterActions,
longRestText,
} = useCharacterEngine();
const dispatch = useDispatch();
const handleSave = () => {
dispatch(
characterActions.longRest(resetMaxHpModifier, adjustConditionLevel)
);
dispatch(
toastMessageActions.toastSuccess(
"Long Rest Taken",
"You have completed a long rest. Relevant abilities have been reset."
)
);
};
const handleRestoreToLife = (restoreType: ShortModelInfoContract) => {
const restoreChoice = restoreType.name === "Full" ? "full" : "1";
dispatch(characterActions.restoreLife(restoreType.id));
dispatch(
toastMessageActions.toastSuccess(
"Character Restored to Life",
`You have been restored to life with ${restoreChoice} HP.`
)
);
};
const handleChangeLongRestType = (value: number | null) => {
const typedPrefKey = characterUtils.getPreferenceKey("longRestType");
if (typedPrefKey !== null) {
dispatch(characterActions.preferenceChoose(typedPrefKey, value));
}
};
useEffect(() => {
const abortController = new AbortController();
if (restMessageLoadingStatus !== DataLoadingStatusEnum.LOADED) {
setRestMessageLoadingStatus(DataLoadingStatusEnum.LOADING);
ApiRequests.getCharacterRestLong({
signal: abortController.signal,
})
.then((response) => {
let message = apiAdapterUtils.getResponseData(response);
if (message !== null) {
dispatch(serviceDataActions.longRestTextSet(message));
}
setRestMessageLoadingStatus(DataLoadingStatusEnum.LOADED);
})
.catch((e) => {
if (abortController.signal.aborted) return;
AppLoggerUtils.handleAdhocApiError(e);
});
}
// If the pane is quickly opened and closed multiple times, we cancel any in-flight requests.
return () => {
abortController.abort();
};
}, [restMessageLoadingStatus]);
const renderRecover = () => {
if (isDead) {
return <p>Your character is dead</p>;
}
const exhaustionIsActive = activeConditions.find(
(condition) => condition.level !== null
);
return (
<>
<p>
{longRestText === null ||
restMessageLoadingStatus === DataLoadingStatusEnum.LOADING
? "Asking the server what will be reset..."
: longRestText}
</p>
<div className={styles.recoverMaxHp}>
<Checkbox
className={styles.checkbox}
id="reset-max-hp"
label="Reset Maximum HP changes during this rest"
checked={resetMaxHpModifier}
onChange={() => setResetMaxHpModifier(!resetMaxHpModifier)}
themed
/>
</div>
{exhaustionIsActive && (
<div className={styles.recoverExhaustion}>
<Checkbox
className={styles.checkbox}
id="recover-exhaustion"
label="Recover 1 Level of Exhaustion during this rest (requires food and drink)"
checked={adjustConditionLevel}
onChange={() => setAdjustConditionLevel(!adjustConditionLevel)}
themed
/>
</div>
)}
</>
);
};
const renderActions = () => {
if (isDead) {
return (
<>
<RestoreLifeManager onSave={handleRestoreToLife} />
</>
);
}
return (
<div className={styles.recoverActions}>
<ThemeButton onClick={handleSave} enableConfirm={true}>
Take Long Rest
</ThemeButton>
<ThemeButton
onClick={() => {
setResetMaxHpModifier(true);
setAdjustConditionLevel(false);
}}
style="outline"
>
Reset
</ThemeButton>
</div>
);
};
return (
<>
<Header>Long Rest</Header>
<div>
<p>
A Long Rest is a period of extended downtimeat least 8
hoursavailable to any creature. During a Long Rest, you sleep for at
least 6 hours and perform no more than 2 hours of light activity, such
as reading, talking, eating, or standing watch.
</p>
<p>
While asleep, you have the Unconscious condition. After you finish a
Long Rest, you must wait at least 16 hours before starting another
one.
</p>
</div>
<div className={styles.longRestType}>
<RadioGroup
className={styles.radioGroup}
themed
title="Long Rest Rules"
name="long-rest-type"
initialValue={preferences.longRestType}
onChange={(e) =>
handleChangeLongRestType(
helperUtils.parseInputInt(e?.target?.value)
)
}
options={[
{
label: "Recover 1/2 Hit Dice",
description: "Use 5e Rules",
value: PreferenceLongRestTypeEnum.HALF,
},
{
label: "Recover all Hit Dice",
description: "Use 5.5e Rules",
value: PreferenceLongRestTypeEnum.FULL,
},
]}
/>
</div>
<div className={styles.recover}>
<h2 className={styles.recoverHeading}>Recover</h2>
{renderRecover()}
</div>
{renderActions()}
<div className={styles.longRestInfo}>
<p>
<strong>
<em>Benefits of the Rest.</em>
</strong>{" "}
To start a Long Rest, you must have at least 1 HP. When you finish the
rest, you gain the following benefits:
</p>
<ul>
<li>
You regain all lost HP and all spent Hit Point Dice. If your HP
maximum was reduced, it returns to normal.
</li>
<li>
If any of your ability scores were reduced, they return to normal.
</li>
<li>
If you have the Exhaustion condition, its level decreases by 1.
</li>
<li>
If you have a feature that is recharged by a Long Rest, it recharges
in the way specified in its description.
</li>
</ul>
<p>
<strong>
<em>Interrupting the Rest.</em>
</strong>{" "}
A Long Rest is stopped by the following interruptions:
</p>
<ul>
<li>Rolling Initiative</li>
<li>Casting a spell other than a cantrip</li>
<li>Taking any damage</li>
<li>1 hour of walking or other physical exertion</li>
</ul>
<p>
If you rested at least 1 hour before the interruption, you gain the
benefits of a Short Rest.
</p>
<p>
You can resume a Long Rest immediately after an interruption. If you
do so, the rest requires 1 additional hour per interruption to finish.
</p>
</div>
</>
);
};