This commit is contained in:
2026-04-29 20:56:59 +08:00
parent fb6f455530
commit 730f485f48
200 changed files with 9881 additions and 2221 deletions

View File

@@ -234,6 +234,55 @@ describe('GameCanvasEntityLayer', () => {
expect(html).toContain('aria-label="好感度变化 +3"');
});
it('keeps battle opponent visible when compat payload misses encounter context', () => {
const hostileNpc = createHostileNpc({
encounter: undefined,
name: '断桥匪首',
description: '刚进入战斗时的旧快照目标',
});
const html = renderToStaticMarkup(
<GameCanvasEntityLayer
companions={[]}
sceneActAmbientEncounters={[]}
currentScenePreset={null}
sceneTransitionToken={0}
isSceneTransitionEntering={false}
isSceneTransitionExiting={false}
transitionSweepPx={320}
sceneTransitionExitDurationS={0.2}
sceneTransitionEntryDurationS={0.2}
companionAnchorLeft="10%"
companionAnchorBottom="20%"
playerBottomOffsetPx={0}
sceneTransitionPhase="idle"
inBattle={true}
onEntitySelect={null}
playerLeft="20%"
playerCharacter={createCharacter()}
playerHp={100}
playerMaxHp={100}
effectivePlayerFacing="right"
effectivePlayerAnimationState={AnimationState.IDLE}
shouldShowPlayerDialogueIcon={false}
dialogueIndicator={null}
npcAffinityEffect={null}
sceneCombatants={[hostileNpc]}
monsters={[]}
getHostileNpcOuterLeft={() => '70%'}
groundBottom="18%"
stageLiftPx={68}
encounter={null}
sideAnchor="15%"
cameraAnchorX={0}
monsterAnchorMeters={3.2}
playerX={0}
/>,
);
expect(html).toContain('查看断桥匪首详情');
expect(html).toContain('from-rose-500 to-red-400');
});
it('does not render affinity effect on a different npc', () => {
const html = renderEntityLayer('npc-other');

View File

@@ -98,6 +98,18 @@ interface GameCanvasEntityLayerProps {
const SCENE_ACT_BACK_ROW_ANCHOR_X_METERS = RESOLVED_ENTITY_X_METERS + 1.08;
const SCENE_ACT_BACK_ROW_OFFSET_PX = [62, -46] as const;
function buildFallbackCombatEncounter(hostileNpc: SceneHostileNpc): Encounter {
return {
id: hostileNpc.id,
kind: 'npc',
npcName: hostileNpc.name,
npcDescription: hostileNpc.description,
npcAvatar: '',
context: hostileNpc.action,
hostile: true,
};
}
function addCssPxOffset(value: string, offsetPx: number) {
return offsetPx === 0 ? value : `calc(${value} + ${offsetPx}px)`;
}
@@ -440,8 +452,7 @@ export function GameCanvasEntityLayer({
</motion.div>
{sceneCombatants.map((hostileNpc, index) => {
const npcEncounter = hostileNpc.encounter;
if (!npcEncounter) return null;
const npcEncounter = hostileNpc.encounter ?? buildFallbackCombatEncounter(hostileNpc);
const hostileRenderKey = [
hostileNpc.id,
npcEncounter.id ?? npcEncounter.npcName,