Honey Village: six model builds + hub frontend, Dockerized for Dokploy

This commit is contained in:
2026-07-15 10:50:12 -04:00
commit 67253bded5
523 changed files with 58879 additions and 0 deletions
+110
View File
@@ -0,0 +1,110 @@
// 共享类型与常量。所有数值/台词的原文在 src/data/ 下,本文件只放结构性定义。
export type Stage = 0 | 1 | 2 | 3 | 4;
/** §6.4 侵蚀阶段矩阵:视听参数唯一真源表 */
export interface StageParams {
saturation: number; // ColorMatrix 饱和度
vignette: number; // 晕影强度 0-1
playbackRate: number; // BGM 速率
lowpass: number; // 低通截止 Hz
birdMuted: boolean; // 鸟鸣声部静音
textLevel: 0 | 1 | 2 | 3; // 0 无 / 1 标点重复(1/80) / 2 同音错字(1/50) / 3 加密(1/10)
negativePerMin: number; // 随机单帧负片频率(次/分钟)
petalBright: boolean; // 花瓣过亮
}
export const STAGE_PARAMS: Record<Stage, StageParams> = {
0: { saturation: 0.90, vignette: 0.00, playbackRate: 1.00, lowpass: 22050, birdMuted: false, textLevel: 0, negativePerMin: 0.0, petalBright: false },
1: { saturation: 1.00, vignette: 0.00, playbackRate: 1.00, lowpass: 22050, birdMuted: false, textLevel: 0, negativePerMin: 0.0, petalBright: false },
2: { saturation: 1.15, vignette: 0.00, playbackRate: 0.97, lowpass: 22050, birdMuted: false, textLevel: 1, negativePerMin: 0.0, petalBright: false },
3: { saturation: 1.30, vignette: 0.30, playbackRate: 0.92, lowpass: 8000, birdMuted: false, textLevel: 2, negativePerMin: 0.0, petalBright: true },
4: { saturation: 1.40, vignette: 0.60, playbackRate: 0.84, lowpass: 4000, birdMuted: true, textLevel: 3, negativePerMin: 0.4, petalBright: true },
};
/** 由幸福值映射阶段(§6.4) */
export function stageOf(happiness: number): Stage {
if (happiness >= 100) return 4;
if (happiness >= 81) return 3;
if (happiness >= 51) return 2;
if (happiness >= 21) return 1;
return 0;
}
export type NpcId =
| 'afu' | 'yuanyuan' | 'dabao' | 'mimi' | 'fuyisheng' | 'guiyeye' | 'bird'
| 'squirrel' | 'hedgehog' | 'fox' | 'pig' | 'chick';
export interface NpcDef {
id: NpcId;
name: string; // 对话框说话者名
spriteKey: string; // spritesheet key
portraitKey: string; // 头像 key(群演无)
offset: number; // §4 阈值偏移(作用于幸福阈值)
expressive: boolean; // 是否参与侵蚀表情(芙医生/龟爷爷/群演不参与)
isExtra: boolean; // 群演
}
export const NPC_DEFS: Record<NpcId, NpcDef> = {
afu: { id: 'afu', name: '阿福', spriteKey: 'npc_afu', portraitKey: 'portrait_afu', offset: 0, expressive: true, isExtra: false },
yuanyuan: { id: 'yuanyuan', name: '圆圆', spriteKey: 'npc_yuanyuan', portraitKey: 'portrait_yuanyuan', offset: 15, expressive: true, isExtra: false },
dabao: { id: 'dabao', name: '大宝', spriteKey: 'npc_dabao', portraitKey: 'portrait_dabao', offset: 0, expressive: true, isExtra: false },
mimi: { id: 'mimi', name: '咪咪', spriteKey: 'npc_mimi', portraitKey: 'portrait_mimi', offset: -10, expressive: true, isExtra: false },
fuyisheng: { id: 'fuyisheng', name: '芙医生', spriteKey: 'npc_fuyisheng', portraitKey: 'portrait_fuyisheng', offset: 0, expressive: false, isExtra: false },
guiyeye: { id: 'guiyeye', name: '龟爷爷', spriteKey: 'npc_guiyeye', portraitKey: 'portrait_guiyeye', offset: 0, expressive: false, isExtra: false },
bird: { id: 'bird', name: '双子鸟', spriteKey: 'npc_bird', portraitKey: 'portrait_bird', offset: 0, expressive: false, isExtra: false },
squirrel: { id: 'squirrel', name: '松鼠', spriteKey: 'extra_squirrel', portraitKey: '', offset: 0, expressive: false, isExtra: true },
hedgehog: { id: 'hedgehog', name: '刺猬', spriteKey: 'extra_hedgehog', portraitKey: '', offset: 0, expressive: false, isExtra: true },
fox: { id: 'fox', name: '狐狸', spriteKey: 'extra_fox', portraitKey: '', offset: 0, expressive: false, isExtra: true },
pig: { id: 'pig', name: '小猪', spriteKey: 'extra_pig', portraitKey: '', offset: 0, expressive: false, isExtra: true },
chick: { id: 'chick', name: '小鸡', spriteKey: 'extra_chick', portraitKey: '', offset: 0, expressive: false, isExtra: true },
};
export const NAMED_NPCS: NpcId[] = ['afu', 'yuanyuan', 'dabao', 'mimi', 'fuyisheng', 'guiyeye', 'bird'];
export const EXTRA_NPCS: NpcId[] = ['squirrel', 'hedgehog', 'fox', 'pig', 'chick'];
/** 地图 key → 场景 key */
export const MAP_SCENES: Record<string, string> = {
house: 'HouseScene',
plaza: 'PlazaScene',
bakery: 'BakeryScene',
shop: 'ShopScene',
clinic: 'ClinicScene',
lake: 'LakeScene',
field: 'FieldScene',
well: 'WellScene',
fog: 'FogScene',
white: 'WhiteScene',
};
export const OUTDOOR_MAPS = ['plaza', 'lake', 'field', 'well', 'fog'];
/** 对话选项种类(§12:温柔/迟疑/否定;accept/refuse 用于可拒绝任务) */
export type ChoiceKind = 'gentle' | 'hesitant' | 'deny' | 'accept' | 'refuse';
export interface DialogueChoice {
label: string;
kind: ChoiceKind;
}
export interface DialoguePayload {
speakerId?: NpcId | 'narrator';
lines: string[];
choices?: DialogueChoice[];
}
export type SadnessKind = 'refuse' | 'deny' | 'idle' | 'cling' | 'rain';
export type SmallInteractionKind = 'water' | 'feed' | 'pat';
export type EndingId = 'E1' | 'E2' | 'E3' | 'E4';
/** 标准三选项 */
export const STANDARD_CHOICES: DialogueChoice[] = [
{ label: '(温柔地回应)', kind: 'gentle' },
{ label: '(迟疑)', kind: 'hesitant' },
{ label: '(否定)', kind: 'deny' },
];
export const GAME_W = 320;
export const GAME_H = 180;
export const MOVE_SPEED = 96;
export const INTERACT_RANGE = 24;