Implement scene-based chapter quest progression
Some checks failed
CI / verify (push) Has been cancelled

This commit is contained in:
2026-04-08 11:58:47 +08:00
parent 9d2fc9e4b8
commit bd9fdcbe31
170 changed files with 18259 additions and 1049 deletions

View File

@@ -12,7 +12,6 @@ import {
type ScenePresetInfo,
type WorldType,
} from '../../types';
import {CharacterAnimator} from '../CharacterAnimator';
import {HostileNpcAnimator} from '../HostileNpcAnimator';
import {MedievalNpcAnimator} from '../MedievalNpcAnimator';
import {getRenderableNpcFacing} from '../npcRenderUtils';
@@ -31,7 +30,6 @@ import {
mapHostileNpcAnimationToCharacterState,
MONSTER_RENDER_OFFSETS,
ROLE_CHARACTER_FRAME_CLASS,
ROLE_CHARACTER_SPRITE_CLASS,
RoleCharacterSprite,
SCENE_TRANSITION_LOWER_COMPANION_DELAY_S,
SCENE_TRANSITION_UPPER_COMPANION_DELAY_S,
@@ -166,19 +164,11 @@ export function GameCanvasEntityLayer({
</div>
)}
<div className={ROLE_CHARACTER_FRAME_CLASS}>
<div
className="h-full w-full"
style={{
transform:
(sceneTransitionPhase === 'idle' ? companion.facing : 'right') === 'left'
? 'scaleX(-1)'
: undefined,
}}
>
<CharacterAnimator
<div className={companion.hp <= 0 ? 'opacity-45 grayscale' : undefined}>
<RoleCharacterSprite
state={sceneTransitionPhase === 'idle' ? companion.animationState : AnimationState.RUN}
character={companion.character}
className={`${ROLE_CHARACTER_SPRITE_CLASS} ${companion.hp <= 0 ? 'opacity-45 grayscale' : ''}`}
facing={sceneTransitionPhase === 'idle' ? (companion.facing ?? 'right') : 'right'}
/>
</div>
</div>
@@ -220,13 +210,13 @@ export function GameCanvasEntityLayer({
ariaLabel={playerCharacter ? `查看${playerCharacter.name}详情` : undefined}
className="relative block"
>
<div className="relative" style={{transform: effectivePlayerFacing === 'left' ? 'scaleX(-1)' : undefined}}>
<div className="relative">
<div className={ROLE_CHARACTER_FRAME_CLASS}>
{playerCharacter && (
<CharacterAnimator
<RoleCharacterSprite
state={effectivePlayerAnimationState}
character={playerCharacter}
className={ROLE_CHARACTER_SPRITE_CLASS}
facing={effectivePlayerFacing}
/>
)}
</div>
@@ -248,15 +238,18 @@ export function GameCanvasEntityLayer({
if (!npcEncounter) return null;
const config = monsters.find(item => item.id === hostileNpc.id);
const renderOffset = MONSTER_RENDER_OFFSETS[hostileNpc.id] ?? {x: 0, y: 0};
const npcMonsterConfig = npcEncounter?.monsterPresetId
const npcCharacter = npcEncounter?.characterId ? getCharacterById(npcEncounter.characterId) : null;
const npcMonsterConfig = !npcCharacter && npcEncounter?.monsterPresetId
? monsters.find(item => item.id === npcEncounter.monsterPresetId) ?? config ?? null
: null;
const npcCharacter = npcEncounter?.characterId ? getCharacterById(npcEncounter.characterId) : null;
const npcSceneSpriteFacing =
npcCharacter
? hostileNpc.facing
: getRenderableNpcFacing(npcEncounter, hostileNpc.facing, {medievalVisual: true});
const npcCombatHpTop = getNpcCombatHpTop(npcEncounter?.characterId, npcEncounter?.monsterPresetId);
const npcCombatHpTop = getNpcCombatHpTop(
npcCharacter ? npcEncounter?.characterId : null,
npcCharacter ? null : npcEncounter?.monsterPresetId,
);
const hostileNpcBottomOffsetPx = npcMonsterConfig
? HOSTILE_NPC_SCENE_BOTTOM_OFFSET_PX
: 0;
@@ -350,7 +343,7 @@ export function GameCanvasEntityLayer({
encounter.kind !== 'treasure' && encounter.characterId
? getCharacterById(encounter.characterId)
: null;
const peacefulMonsterConfig =
const peacefulMonsterConfig = !peacefulResolvedCharacter &&
encounter.kind === 'npc' && encounter.monsterPresetId
? monsters.find(item => item.id === encounter.monsterPresetId) ?? null
: null;