This commit is contained in:
2026-04-26 20:50:58 +08:00
parent a3a9bfa194
commit 67161bd6d1
142 changed files with 3349 additions and 10674 deletions

View File

@@ -523,7 +523,7 @@ describe('createStoryChoiceActions', () => {
expect(handleNpcInteraction).toHaveBeenCalledWith(option);
});
it('reopens npc chat instead of running generic follow-up after local npc victory', async () => {
it('uses deterministic continue option after local npc victory', async () => {
const encounter: Encounter = {
id: 'npc-opponent',
kind: 'npc',
@@ -611,31 +611,31 @@ describe('createStoryChoiceActions', () => {
await handleChoice(option);
expect(handleNpcBattleConversationContinuation).toHaveBeenCalledWith(
expect(handleNpcBattleConversationContinuation).not.toHaveBeenCalled();
expect(setGameState).toHaveBeenCalledWith(
expect.objectContaining({
nextState: expect.objectContaining({
currentBattleNpcId: null,
currentNpcBattleMode: null,
currentNpcBattleOutcome: null,
}),
encounter,
actionText: '挥刀抢攻',
resultText: '山道客已经败下阵来。胜利奖励:无战利品。',
battleMode: 'fight',
currentBattleNpcId: null,
currentNpcBattleMode: null,
currentNpcBattleOutcome: null,
inBattle: false,
}),
);
expect(generateStoryForState).not.toHaveBeenCalled();
expect(setCurrentStory).not.toHaveBeenCalledWith(
createFallbackStory('战后续写'),
expect(setCurrentStory).toHaveBeenCalledWith(
expect.objectContaining({
text: '山道客已经败下阵来。胜利奖励:无战利品。',
options: [
expect.objectContaining({
functionId: 'story_continue_adventure',
actionText: '继续前进',
}),
],
}),
);
});
it('injects an escape resolution into the immediate story context before ai continuation', async () => {
it('settles escape locally without ai continuation', async () => {
const mockedGenerateNextStep = vi.mocked(generateNextStep);
mockedGenerateNextStep.mockResolvedValue({
storyText: '你落到山道外侧,呼吸总算稳了下来。',
options: [],
});
const state = {
...createBaseState(),
@@ -667,6 +667,7 @@ describe('createStoryChoiceActions', () => {
playerX: -1.2,
};
const setBattleReward = vi.fn();
const setCurrentStory = vi.fn();
const incrementRuntimeStats = vi.fn((inputState: GameState) => inputState);
const buildStoryContextFromState = vi.fn(() => ({
playerHp: 100,
@@ -685,7 +686,7 @@ describe('createStoryChoiceActions', () => {
currentStory: createFallbackStory(),
isLoading: false,
setGameState: vi.fn(),
setCurrentStory: vi.fn(),
setCurrentStory,
setAiError: vi.fn(),
setIsLoading: vi.fn(),
setBattleReward,
@@ -723,20 +724,11 @@ describe('createStoryChoiceActions', () => {
await handleChoice(option);
expect(mockedGenerateNextStep).toHaveBeenCalledTimes(1);
const history = mockedGenerateNextStep.mock.calls[0]?.[3] as StoryMoment[];
expect(history.map((entry) => `${entry.historyRole}:${entry.text}`)).toEqual([
'action:挥刀抢攻',
'result:你已成功逃脱,与山狼的交战已经被甩开,对方暂时落在身后,当前不再处于战斗状态。',
]);
expect(buildStoryContextFromState).toHaveBeenCalledWith(
expect(mockedGenerateNextStep).not.toHaveBeenCalled();
expect(buildStoryContextFromState).not.toHaveBeenCalled();
expect(setCurrentStory).toHaveBeenCalledWith(
expect.objectContaining({
inBattle: false,
sceneHostileNpcs: [],
}),
expect.objectContaining({
lastFunctionId: 'battle_escape_breakout',
recentActionResult: '你已成功逃脱,与山狼的交战已经被甩开,对方暂时落在身后,当前不再处于战斗状态。',
text: '你已成功逃脱,与山狼的交战已经被甩开,对方暂时落在身后,当前不再处于战斗状态。',
}),
);
expect(setBattleReward).toHaveBeenCalledTimes(1);