1
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
DialogueBubbleIcon,
|
||||
type GameCanvasEntitySelection,
|
||||
GENERIC_NPC_SCENE_SCALE,
|
||||
getBattleCompanionSlotOffset,
|
||||
getCompanionSlotOffset,
|
||||
getEncounterCharacterBottomOffsetPx,
|
||||
getEncounterCharacterOpponentBottom,
|
||||
@@ -222,11 +223,23 @@ export function GameCanvasEntityLayer({
|
||||
const [combatFeedbackEvents, setCombatFeedbackEvents] = useState<CombatFeedbackEvent[]>([]);
|
||||
const previousCombatSamplesRef = useRef<Map<string, CombatFeedbackHealthSample> | null>(null);
|
||||
const combatFeedbackSequenceRef = useRef(0);
|
||||
const hasCombatAfterimage = useMemo(
|
||||
() =>
|
||||
combatFeedbackEvents.length > 0 ||
|
||||
sceneCombatants.some(
|
||||
(hostileNpc) =>
|
||||
hostileNpc.hp < hostileNpc.maxHp ||
|
||||
hostileNpc.animation === 'attack' ||
|
||||
hostileNpc.animation === 'die',
|
||||
),
|
||||
[combatFeedbackEvents.length, sceneCombatants],
|
||||
);
|
||||
const shouldRenderCombatPresentation = inBattle || hasCombatAfterimage;
|
||||
const shouldRenderPeacefulEncounter =
|
||||
Boolean(encounter) && (!inBattle || sceneCombatants.length === 0);
|
||||
const combatHealthSamples = useMemo<CombatFeedbackHealthSample[]>(
|
||||
() => {
|
||||
if (!inBattle) return [];
|
||||
if (!shouldRenderCombatPresentation) return [];
|
||||
|
||||
return [
|
||||
{key: 'player', kind: 'player', hp: playerHp},
|
||||
@@ -242,7 +255,7 @@ export function GameCanvasEntityLayer({
|
||||
})),
|
||||
];
|
||||
},
|
||||
[companions, inBattle, playerHp, sceneCombatants],
|
||||
[companions, playerHp, sceneCombatants, shouldRenderCombatPresentation],
|
||||
);
|
||||
const combatFeedbackByTarget = useMemo(() => {
|
||||
const feedbackByTarget = new Map<string, CombatFeedbackEvent[]>();
|
||||
@@ -259,7 +272,7 @@ export function GameCanvasEntityLayer({
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!inBattle) {
|
||||
if (!shouldRenderCombatPresentation) {
|
||||
previousCombatSamplesRef.current = null;
|
||||
setCombatFeedbackEvents([]);
|
||||
return;
|
||||
@@ -283,12 +296,14 @@ export function GameCanvasEntityLayer({
|
||||
previousCombatSamplesRef.current = new Map(
|
||||
combatHealthSamples.map(sample => [sample.key, sample]),
|
||||
);
|
||||
}, [combatHealthSamples, inBattle]);
|
||||
}, [combatHealthSamples, shouldRenderCombatPresentation]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{companions.map(companion => {
|
||||
const slotOffset = getCompanionSlotOffset(companion.slot);
|
||||
const slotOffset = inBattle
|
||||
? getBattleCompanionSlotOffset(companion.slot)
|
||||
: getCompanionSlotOffset(companion.slot);
|
||||
const feedbackTargetKey = `companion:${companion.npcId}`;
|
||||
const feedbackEvents = combatFeedbackByTarget.get(feedbackTargetKey) ?? [];
|
||||
const companionFacing = companion.facing ?? 'right';
|
||||
@@ -314,7 +329,7 @@ export function GameCanvasEntityLayer({
|
||||
style={{
|
||||
left: companionAnchorLeft,
|
||||
bottom: companionAnchorBottom,
|
||||
zIndex: getSceneEntityZIndex(playerBottomOffsetPx + slotOffset.bottom),
|
||||
zIndex: getSceneEntityZIndex(playerBottomOffsetPx + slotOffset.bottom) + (inBattle ? 1 : 0),
|
||||
transition: 'left 260ms linear, bottom 180ms ease',
|
||||
}}
|
||||
>
|
||||
@@ -336,7 +351,7 @@ export function GameCanvasEntityLayer({
|
||||
className="relative flex w-28 flex-col items-center"
|
||||
>
|
||||
<CombatFeedbackNumbers events={feedbackEvents} onDone={removeCombatFeedbackEvent} />
|
||||
{inBattle && (
|
||||
{shouldRenderCombatPresentation && (
|
||||
<div
|
||||
className="absolute left-1/2 -translate-x-1/2"
|
||||
style={{top: `${CHARACTER_COMBAT_HP_TOP_PX}px`}}
|
||||
@@ -385,7 +400,7 @@ export function GameCanvasEntityLayer({
|
||||
events={combatFeedbackByTarget.get('player') ?? []}
|
||||
onDone={removeCombatFeedbackEvent}
|
||||
/>
|
||||
{inBattle && (
|
||||
{shouldRenderCombatPresentation && (
|
||||
<div
|
||||
className="absolute left-1/2 -translate-x-1/2"
|
||||
style={{top: `${CHARACTER_COMBAT_HP_TOP_PX}px`}}
|
||||
@@ -484,7 +499,7 @@ export function GameCanvasEntityLayer({
|
||||
className="relative flex w-28 flex-col items-center"
|
||||
>
|
||||
<CombatFeedbackNumbers events={feedbackEvents} onDone={removeCombatFeedbackEvent} />
|
||||
{inBattle && (
|
||||
{shouldRenderCombatPresentation && (
|
||||
<div
|
||||
className="absolute left-1/2 -translate-x-1/2"
|
||||
style={{top: `${npcCombatHpTop}px`}}
|
||||
|
||||
Reference in New Issue
Block a user