我从2019年开始写作《马克西米利安》。这是一部法国心理惊悚的视觉小说,设定在1926年的波士顿,使用Twine/SugarCube构建,于10月26日在Steam上发布,参加Steam恐怖节。四年左右,我停止计算我已经扔掉的架构决策的次数,开始计算我实际上学到的东西。以下是四个我在第一年会给自己的建议。

简要说来,经过七年和1755个叙事节点后:

- 我试图独自承担太多,太长时间。只有每个领域都有自己的专家,项目才变得可行。
- 我尝试的所有生产力系统都无法适应我的实际工作方式。因此,我不得不自己构建一个系统,包括放弃卡住的场景。
- 记录系统和代码一样严格。未来的你是一个陌生人,谁不会记得 $exor = 1000 的含义。
- 在分支式的fiction中,没有决策是局部的。结构是一个网,一个链条。

一些背景:

《马克西米利安》是一部长篇叙事恐怖项目,参加2026年的IFComp。原版是法语的。英语版本正在由一位具有高学术背景的文学翻译人员进行适应——这不是一个“翻译”过程,而是一部全面的文学重写,旨在在另一种语言中保持句子。

团队有四人,都是远程工作:我负责写作和开发,Solynk负责插画,Larant负责音乐,Lucia负责英语适应,我的兄弟负责所有市场相关事务,以免我需要思考。

我是一个自学者。我从写作开始,来自编程。这种情况影响了几乎所有我的错误——和我即将描述的大部分。

如果你是一位作家或艺术家,正在使用Twine,Ren'Py或自定义引擎构建一个项目,我认为以下的教训转移。如果你是一个受过训练的开发者,你会大部分时间阅读这篇文章并点头同意明显的部分。这没问题。这些并不是我开始时明显的。

关于工具链的一点注释,因为这个问题总是会出现。2019年,我选择了Twine,因为SugarCube是适合我需要的密集互动叙事的工具。今天我也会选择它。这个帖子不是为了辩护这个选择,而是为了描述我必须解决的问题。

1. 我试图独自承担太多,太长时间。

在前几年里,我试图自己处理几乎所有的领域:写作,结构,技术实施,早期视觉方向,甚至音乐的第一尝试。其中一些是预算问题。大部分是因为我认为因为我有一个清晰的愿景,所以我可以自己执行每个部分。

这个假设是错误的。每个领域我触及的东西,除了写作,都会减慢项目的进度并产生我后来必须重做的输出。转变发生在我接受了一个好的专家不仅快,还会带来自己的领域语法,一个通才会错过的东西。Solynk不仅仅是插画,他会阅读手稿并回答它。Larant不仅仅是创作一个气氛,他会创作一个情感结构。Lucia不仅仅是翻译句子,她会重建文学语法从目标语言内部。

所以这个教训不是“委托”,而是错误的合作者比没有合作者更糟糕,而且正确的一个会改变工作的方式你无法预见。慢慢地雇佣,选择对齐而不是只是技巧,可能是我做出的最高杠杆决策。

2. 我尝试的所有生产力系统都无法适应我的实际工作方式。

我尝试了很多。Agile风格的冲刺在文学写作中感觉很愚蠢。严格的每日字数会产生我必须扔掉的文本。GTD系统在一个月内都会崩溃。最后我停止寻找合适的方法,开始从我实际上如何工作来构建一个。

我落地的系统有两个不寻常的特点。

第一个是,我不再与卡住的段落作斗争。如果一个场景在超过三个会话后仍然卡住,我会离开它,几个星期后再回来。九次中有十,阻碍的障碍会变得临时,场景在二十分钟内就会解锁。第十次,障碍是真实的,间隔的时间会给予我距离来看实际上需要改变什么。

第二个是,我会对直觉作为一个值得信赖的信号,即使我不能解释为什么。这个项目如此之长,争论的东西通常是已经做过的事情。真正的突破往往来自一个方向你只在之后才能给出名字。

如果有帮助,借用其他人的形状。但是不要试图居住于一个为另一个有着不同性格的人设计的过程。

3. 记录系统和代码一样严格。

这是我如果我重新写这个帖子给刚开始的人,我会把它放在第一位。

Twine并没有为长篇分支式叙事提供很多架构支持,所以我自己构建了一个手工的文件系统。一个命名约定,任意的嵌套深度:C代表章节,j代表日,R代表梦,数字代表涉及的节点。真实的段落名称最终看起来像c_1_r_2_2_1_1_1_1_1。我的外部系统中的每个卡片都将其变量与其叙事背景联系起来。这个部分会拯救我——到某个程度。

但是,我选择的变量命名在开始时是错误的。我使用字母。a = 0 到 4,然后a1a2等。紧凑,抽象,六个月后几乎不可读。应该从一开始就使用$search_perso$biblio_univ。可读性成本将为零。调试成本的代价是巨大的。

我还犯了其他初学者错误,值得被命名,因为SugarCube在大多数情况下会静默失败。

我将混合类型放在同一个变量中。$tele(电报)有时会包含一个与$day相关的数字,有时是字符串 "done"。比较一个整数和一个字符串可以静默失败在SugarCube中——没有抛出错误,只有一个错误的结果。始终使用一个变量,一个类型。

我使用任意的哨兵值来表示“不可能的状态”。 $exor = 1000 表示驱逐是不可能的,基于假设这个值将不会与其他任何东西冲突。然而,它确实会冲突,第一次路径推 $exor 上 2 以上的值通过合法的游戏。一个单独的 $exor_impossible 布尔值会防止整个类别的错误。

如果我今天开始,我会使用Obsidian和Dataview插件来持有架构作为一个连接的节点系统,并使用Tweego在命令行上工作。两个都会拯救我几个月。如果你正在开始一个Twine项目,任何真正的大小,请在你写第一个段落之前看看它们。

这个更深的教训是。

超过1700个叙事条件在七年里积累了。十个测试者工作了手稿。整个路径仍然在几年后未被走过。有一次我几乎停止了。是什么让我回到它的是,使用AI辅助调试过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过滤过