📝 应用描述
明末崇祯六年,洛阳至扬州千里护送。文字冒险多结局,忠于原作剧情,约 20 分钟。
📋 详细信息
| 应用ID |
epao_mingmo_qianlixing |
| 名称 |
饿殍:明末千里行 |
| 版本 |
v1 |
| 文件大小 |
453.1 KB |
| 上传时间 |
2026-07-29 21:09:05 |
| 状态 |
✅ 已启用 |
| 权限 |
storage |
📁 资源文件 (6)
assets/scene_depart.webp
查看 »
assets/scene_inn.webp
查看 »
assets/scene_river.webp
查看 »
assets/scene_luoyang.webp
查看 »
assets/scene_yangzhou.webp
查看 »
💡 界面预览 (main.lua)
📄 Lua 源码
-- =============================================================
-- 饿殍:明末千里行 —— Oldchat CIP 小程序 v1.0
-- 原作:零创游戏《饿殍:明末千里行》
-- =============================================================
-- 严格遵循 CIP 规范:
-- 1. 顶层只 return 一个 ui.page
-- 2. 受控更新用 app.set_text / set_image / set_visible
-- 3. 仅用 storage 权限,离线运行
-- 4. main.lua 大小控制在 512 KiB 以内
-- =============================================================
-- ---------- 存档 ----------
local STORAGE_KEY = "epao_save_v1"
local function load_state()
local raw = app.storage_get(STORAGE_KEY)
if not raw or raw == "" then return nil end
local node = raw:match("node:([^|]+)")
if not node then return nil end
local flags_str = raw:match("flags:([^|]*)") or ""
local flags = {}
for flag in flags_str:gmatch("[^,]+") do
if flag ~= "" then flags[flag] = true end
end
return { node = node, flags = flags }
end
local function save_state()
local list = {}
for k, v in pairs(state.flags) do
if v then list[#list+1] = k end
end
local raw = "node:" .. state.node .. "|flags:" .. table.concat(list, ",")
app.storage_set(STORAGE_KEY, raw)
end
-- ---------- 状态(全局) ----------
state = {
node = "menu",
flags = {},
}
local saved = load_state()
if saved and type(saved.node) == "string" and saved.node ~= "" then
state.node = saved.node
state.flags = saved.flags or {}
end
-- ---------- 故事数据 ----------
-- 每个节点:
-- chapter, title, image?, prose, choices = { {label, next, flag?}, ... }
local FLAG_NAME = {
soft = "忍让",
warm = "温和",
spoke = "她开了口",
guard_on = "警觉",
feign = "装醉",
feign_ok = "装醉未露",
told_truth = "揭开真相",
silver_left = "留下银两",
wounded = "受伤",
fought = "见血",
spared = "未下死手",
departed = "离洛阳",
}
local S = {}
S.prologue = {
chapter = "序章",
title = "东关客店 · 崇祯六年腊月廿三",
image = "scene_luoyang",
prose =
"洛阳东关,腊月廿三,小雪。\n\n" ..
"我从北市接了活,顶着一身寒气走进东关这家小客店,推门便闻到一股炭火味。" ..
"堂中坐着赵掌柜,穿一身半旧的石青棉袍,头戴暖帽,见我来了,挥挥手把堂倌屏退。\n\n" ..
"『良爷,坐。』他从袖中摸出一只小布包,推过来。\n\n" ..
"我打开。\n\n" ..
"三十两,纹银,码得整齐,光看色相便知是官银。我做了十几年脚夫,见过的银子不少,但这样的整锭摆在面前,心里仍是一跳。\n\n" ..
"『这一单,送到扬州。』赵掌柜压低声音,『送一个人。亲眷女孩,父母双亡,投奔扬州姑母。』\n\n" ..
"我没应声,只是端起那碗已经温好的黄酒,抿了一口。\n\n" ..
"赵掌柜朝里屋扬了扬下巴。门帘一动,一个孩子被领了出来。\n\n" ..
"她低着头,不见礼,也不抬头。瘦,十四五岁上下。面有病色,颊上不见半点血色。发枯黄,拿一根粗布条子系着。\n\n" ..
"她走到屋中央,站定,像一截插在土里的枯枝。\n\n" ..
"一双手很瘦,指节突出,手背上隐约有旧伤的痕迹。\n\n" ..
"她没看我。\n\n" ..
"—— 这趟活,说不上凶险,却也说不上干净。",
choices = {
{ label = "收下银子,带她启程", next = "act1_depart" },
{ label = "再问赵掌柜几句", next = "ask_zhao" },
{ label = "拒绝这单活", next = "refuse" },
}
}
S.ask_zhao = {
chapter = "序章",
title = "再问一句",
image = "scene_luoyang",
prose =
"我把银子推回去一寸。\n\n" ..
"『这孩子……真是您家外甥女?』\n\n" ..
"赵掌柜的笑意僵了一瞬。他没正面回答,只是端起酒碗,慢慢喝了一口。\n\n" ..
"『良爷,做咱们这行的,最忌讳多问。』\n\n" ..
"『您只管送到扬州,人交给接头那位,事毕拿尾款。旁的事,烂在肚子里。』\n\n" ..
"『三十两,够一家老小过两年。』\n\n" ..
"他看着我的眼睛,声音压得更低:『这孩子是死契。活着送到,您就算完了。』\n\n" ..
"门外又飘起雪。屋里炭火噼啪。\n\n" ..
"—— 我听懂了。",
choices = {
{ label = "收下银子,带她启程", next = "act1_depart" },
{ label = "还是不接", next = "refuse" },
}
}
S.refuse = {
chapter = "序章 · 终",
title = "放下银子",
image = "scene_luoyang",
prose =
"我没接。\n\n" ..
"『赵掌柜,这趟活儿,我接不下。』\n\n" ..
"赵掌柜脸色一沉,看了我很久。他没再劝,只是把银子收回袖中,把孩子重新带回了里屋。\n\n" ..
"我站在雪里,看着门帘落下。\n\n" ..
"—— 后来我听说,那孩子最后是被另一个人领走的。\n\n" ..
"再后来,洛阳城被流寇围了三天,死了很多人。\n\n" ..
"赵掌柜的小院,也被一把火烧了。\n\n" ..
"我常常想,那一夜我若是接了银子,事情会不会不一样?又常常想,我没有接,是不是对的?\n\n" ..
"—— 有些事,没有下文,也算下文。",
choices = {
{ label = "回到主菜单", next = "menu" },
}
}
S.act1_depart = {
chapter = "第一章",
title = "出洛阳 · 腊月风寒",
image = "scene_depart",
prose =
"腊月廿四清晨,天还没全亮,我便领着她出了洛阳东门。\n\n" ..
"她跟在我身后三步远,背着一只粗布包袱,一路上一句话也不说。我问她叫什么,她不答。我问她多大了,她也不答。我问她是哪里人,她只是轻轻摇了摇头。\n\n" ..
"出了城,洛水桥头,桥面结着一层薄冰。我扶她过去的时候,她躲了一下我的手,自己小心翼翼地摸着桥栏,一步一步挪了过去。\n\n" ..
"过了桥,官道两旁是荒芜的田。地里只剩枯黄的麦茬,偶尔能见到新起的坟包。新土的颜色比旧土深,新坟前往往插着一根白幡,在风里抖。\n\n" ..
"走到午时,我俩在路边一座破亭子里歇脚。\n\n" ..
"我掏出自己带的两个冷炊饼,递了一个给她。\n\n" ..
"她没接。\n\n" ..
"她在自己包袱里,翻找了好一会儿,摸出一块油纸包着的肉——夹在热蒸饼里,带着余温,香气扑鼻。\n\n" ..
"她没分我。她也不看我。\n\n" ..
"她只是把那肉从油纸里小心取出来,小口小口地、仔细地吃。\n\n" ..
"我嚼着自己的冷炊饼。嚼着嚼着,听她吃那肉,听得清清楚楚。\n\n" ..
"—— 那肉的味儿,闻起来,不太像羊肉。\n\n" ..
"我张了张嘴,又合上了。",
choices = {
{ label = "忍住不开口,假装没看见", next = "act1_silent", flag = "soft" },
{ label = "问她一句:『这是哪里买的?』", next = "act1_ask", flag = "spoke" },
{ label = "把冷炊饼也递过去,低声说:『吃吧。』", next = "act1_share", flag = "warm" },
}
}
S.act1_silent = {
chapter = "第一章 · 风雪",
title = "没说出口",
image = "scene_depart",
prose =
"我没说话。\n\n" ..
"我嚼完我的冷炊饼,把油纸拍了拍,塞回怀里。\n\n" ..
"她吃完了那块肉,舔了舔手指,把油纸也仔细折好,塞进自己的包袱。\n\n" ..
"她始终没看我一眼。\n\n" ..
"—— 我忽然想:这一路上,她要吃几块这样的肉?我能不能护住她,把她送到扬州?送到之后,她会被怎么安排?\n\n" ..
"我没问。\n\n" ..
"—— 我只是站起身,拍了拍屁股上的土,重新上路。\n\n" ..
"她跟在我身后,三步远,跟出城时一模一样。",
choices = {
{ label = "继续赶路", next = "act2_river" },
}
}
S.act1_ask = {
chapter = "第一章 · 风雪",
title = "问了一句",
image = "scene_depart",
prose =
"『这是哪里买的?』\n\n" ..
"她停了一下。\n\n" ..
"那半块肉还捏在手里,她抬头看了我一眼,眼神里带着一种我说不上来的东西——像是警惕,又像是询问。\n\n" ..
"『……过路的人给的。』\n\n" ..
"声音很轻,像怕被谁听见。\n\n" ..
"—— 这是她说的第一句话。\n\n" ..
"她把剩下的肉用油纸仔细包好,塞回包袱深处。\n\n" ..
"我没再问。我只是又看了她一眼。\n\n" ..
"她低下头,又成了那个一截枯枝一样的女孩子。\n\n" ..
"—— 但我心里明白,从这一句起,事情就不一样了。",
choices = {
{ label = "继续赶路", next = "act2_river" },
}
}
S.act1_share = {
chapter = "第一章 · 风雪",
title = "递了过去",
image = "scene_depart",
prose =
"我没说话,只是把手里的冷炊饼也递过去,低声说:『吃吧。』\n\n" ..
"她愣了一下。\n\n" ..
"那是这一路上她第一次正眼看我。眼睛里有一点我说不上来的东西——不是感激,倒像是一个人在判断另一个人会不会害她。\n\n" ..
"她没接炊饼。\n\n" ..
"她看了看手里的肉,又看了看我。\n\n" ..
"最后她把剩下的那半块肉,掰了一小块下来,放在油纸上,朝我推了推。\n\n" ..
"我看了看那块肉。\n\n" ..
"我没吃。我只把油纸收好,还给了她。\n\n" ..
"她把那小块肉,又自己吃了。\n\n" ..
"—— 我后来想,她其实是想分我的。可她不知道,我是嫌那肉的味道。\n\n" ..
"—— 我更不知道,她是从哪里弄来这肉的。",
choices = {
{ label = "继续赶路", next = "act2_river" },
}
}
S.act2_river = {
chapter = "第二章",
title = "孟津 · 黄河渡口",
image = "scene_river",
prose =
"行至孟津渡口,已近年关。\n\n" ..
"远远便听见人声嘈杂,像潮水。\n\n" ..
"我领着她走近。河滩上黑压压一片,挤满了要过河的流民。男女老幼,衣衫褴褛,面黄肌瘦,有的抱着孩子,有的扶着老人,有的推着独轮车,车上一只破箱、一床烂被。\n\n" ..
"路边的土里插着许多草标,有的还带着血。草标上写着价:『女孩八岁,三斗米』『男孩六岁,四斗米』『老母能洗衣做饭,半斗米』。\n\n" ..
"半斗米。\n\n" ..
"我下意识攥紧了刀柄。\n\n" ..
"船家蹲在船头,见了我这副打扮,问:『客官是过河?』我点头。船家叹一口气,低声说:『今年这河上漂的尸体,比往年多十倍。能走的都往南跑。』\n\n" ..
"我领着她沿河滩走。忽然我闻到一股腥臭。\n\n" ..
"我低头。\n\n" ..
"一处被乱石盖着的尸首,被啃得七零八落。头发散在地上。手指被剁去了三根。\n\n" ..
"我下意识伸手,把身后那孩子的眼睛挡了一下。\n\n" ..
"她没挣扎。\n\n" ..
"在渡口,一个穿破袄的青年,站在一块大石头上,远远看着我们这一老一少。\n\n" ..
"他的眼神不像流民。倒像是在认人。",
choices = {
{ label = "怒目瞪回去,把那青年逼退", next = "act2_glare", flag = "guard_on" },
{ label = "装作没看见,低头带穗上船", next = "act2_ignore" },
{ label = "把穗护在身后,手按刀柄", next = "act2_cover", flag = "guard_on" },
}
}
S.act2_glare = {
chapter = "第二章 · 河风",
title = "怒目相向",
image = "scene_river",
prose =
"我转过身,直直瞪着那青年。\n\n" ..
"他的目光僵了一瞬。\n\n" ..
"我没出声。我只是把刀从鞘里抽出半寸,又送回去。\n\n" ..
"—— 这是江湖上最明白的警告。\n\n" ..
"他低了头,慢慢退进了人堆里。\n\n" ..
"我领着穗上船。\n\n" ..
"船离岸的时候,我余光扫到那青年还站在那块大石头上,看我们的方向。\n\n" ..
"—— 后来我才明白,他大概已经确认了什么。\n\n" ..
"—— 他确认的,不是我们的路,是穗。",
choices = {
{ label = "上船,过河", next = "act3_inn" },
}
}
S.act2_ignore = {
chapter = "第二章 · 河风",
title = "装作没看见",
image = "scene_river",
prose =
"我拽了拽穗的袖口,没让她回头,径直上了船。\n\n" ..
"船上挤得厉害,人贴着人。她被挤到了我身前,我用肩膀给她挡出一小块地方。\n\n" ..
"她抬头看了我一眼,眼神里有一点感激。\n\n" ..
"船离岸。\n\n" ..
"我余光扫到那青年还站在岸边,看我们的方向。\n\n" ..
"—— 他没有跟上来。\n\n" ..
"船上有人哭,有人咳嗽,有人低声哄着怀里的孩子。河风带着水腥气,吹得人脸上发疼。\n\n" ..
"我突然想起来,我已经三天没睡过一个囫囵觉。\n\n" ..
"—— 但我不能睡。这一路,事多。",
choices = {
{ label = "上船,过河", next = "act3_inn" },
}
}
S.act2_cover = {
chapter = "第二章 · 河风",
title = "把她护在身后",
image = "scene_river",
prose =
"我侧身,把穗挡在身后,手按在了刀柄上。\n\n" ..
"那青年的目光和我撞了一下。\n\n" ..
"几息之后,他才慢慢转身,消失在了人堆里。\n\n" ..
"—— 他的手,一直揣在怀里,看不清有没有东西。\n\n" ..
"我领着穗上船,一路上都把她挡在身侧。她不说话,只是跟得很紧。\n\n" ..
"船离岸时,我又回头看了一眼。\n\n" ..
"—— 那块大石头上,空了。\n\n" ..
"我心里却越发不踏实:他没跟上来,是不是绕了路,先去前面等我们?\n\n" ..
"船家说再有一日就到对岸。我点头,心里默默算着,前面还有什么要防的。",
choices = {
{ label = "上船,过河", next = "act3_inn" },
}
}
S.act3_inn = {
chapter = "第三章",
title = "中州 · 小客店",
image = "scene_inn",
prose =
"过了黄河,又走了两日。\n\n" ..
"行至中州(今郑州一带)一处小镇,天色已晚,投到路边一家小客店。\n\n" ..
"店不大,门脸陈旧,但还能住人。要了间房,一床一桌一盏油灯。简陋,但能挡风。\n\n" ..
"掌柜姓李,五十多岁,左腿瘸,见我领着个孩子,只看了一眼,没多问。端来两碗热汤面、一壶浊酒。\n\n" ..
"穗吃得很少。她把面夹起来又放下,反复几次,最后只喝了半碗汤。\n\n" ..
"我问她:『不饿?』\n\n" ..
"她摇了摇头。\n\n" ..
"—— 我注意到,她那只包袱,从进城起,就被她紧紧抱在怀里,从不离手。\n\n" ..
"夜里,油灯跳了跳。\n\n" ..
"有人敲门。\n\n" ..
"我握住了枕边的朴刀。\n\n" ..
"『客官,借宿一晚。』外面传来一个男人的声音,沙哑,像是走了很远的路,『同乡,搭个伴。』\n\n" ..
"我犹豫了一息。开了门。\n\n" ..
"进来的是个五十岁上下的男人,灰布袄,黑面皮,鞋上全是泥。一双眼睛,带着一种说不清的疲惫。\n\n" ..
"他看了看床上的穗,又看了看我。\n\n" ..
"『这姑娘是您的女儿?』\n\n" ..
"『受人之托,送往扬州。』我说。\n\n" ..
"他没再问。他只是笑了笑,坐到桌边,从怀里摸出一壶酒,倒了三碗。\n\n" ..
"灯又跳了一下。\n\n" ..
"穗背对着我们,像是睡着了。\n\n" ..
"那男人端起酒碗,没喝,只是看着油灯,然后低声说——\n\n" ..
"『若您能放过她,我愿出更高价。』",
choices = {
{ label = "接过酒,问他:『你是她的什么人?』", next = "act3_ask_who" },
{ label = "不接酒,手按刀柄:『喝完这碗,就走。』", next = "act3_warn" },
{ label = "装醉,看他下一步要做什么", next = "act3_feign", flag = "feign" },
}
}
S.act3_ask_who = {
chapter = "第三章 · 油灯下",
title = "问了一句",
image = "scene_inn",
prose =
"我接过酒,没喝,放在桌角。\n\n" ..
"『你是她的什么人?』\n\n" ..
"他沉默了很久。\n\n" ..
"油灯的火苗在他脸上跳。他的眼眶红了一下,又沉下去了。\n\n" ..
"『—— 她爹。』\n\n" ..
"我看了他一眼,没说话。\n\n" ..
"『不。叔父。』他改口说,声音更哑,『我是她叔父。她爹死了。她娘也死了。家里欠了债,卖了她。』\n\n" ..
"『如今我后悔了。』\n\n" ..
"『带不走她,我心里这关过不去。』\n\n" ..
"『—— 求您,放过她。』\n\n" ..
"他忽然起身,要朝我跪下。我伸手拦住了他。\n\n" ..
"油灯又跳了一下。床上,穗背对着我们,可她的肩,抖了一下。\n\n" ..
"—— 我心里明白:她没睡着。",
choices = {
{ label = "把真相告诉她,让她自己决定", next = "act3_truth", flag = "told_truth" },
{ label = "继续装睡,看他下一步要做什么", next = "act3_wait" },
{ label = "让他今晚就走,别再生事", next = "act3_expel" },
}
}
S.act3_warn = {
chapter = "第三章 · 油灯下",
title = "下了逐客令",
image = "scene_inn",
prose =
"我没接酒。手按在刀柄上,看着他。\n\n" ..
"『喝完这碗,就走。』\n\n" ..
"他看了我很久。\n\n" ..
"他端起酒碗,真的喝完了。\n\n" ..
"然后他站起来,朝我点了点头。\n\n" ..
"走到门口,他回头,低声说:『这孩子,是被她亲爹卖去扬州的。您……真的明白吗?』\n\n" ..
"我没回答。\n\n" ..
"门关上了。\n\n" ..
"夜里再没动静。\n\n" ..
"—— 可是,我心里开始不踏实了。\n\n" ..
"床上的穗,翻了个身,背对着我。我看不见她的脸。\n\n" ..
"—— 我猜,她也没睡着。",
choices = {
{ label = "第二天启程", next = "act4_decide" },
}
}
S.act3_feign = {
chapter = "第三章 · 油灯下",
title = "装醉",
image = "scene_inn",
prose =
"我接过酒,装作喝了一大口,却只让酒沾了沾唇。\n\n" ..
"我开始说些醉话,拍桌子,骂官府,骂这世道——一直演到趴在桌上『睡着』。\n\n" ..
"那男人在桌边坐到油灯燃尽,没再说一句话。\n\n" ..
"最后,我听见他叹了口气。\n\n" ..
"他起身,在桌上放下了几块碎银——比他给我的多得多。\n\n" ..
"然后他走了。\n\n" ..
"—— 走之前,他低声说了一句:『——对不起。』\n\n" ..
"我听着他走远了,才睁开眼。\n\n" ..
"油灯已经快燃尽了。床上的穗,背对着我,肩头还在抖。\n\n" ..
"—— 我心里清楚:她也知道,她是谁。",
choices = {
{ label = "第二天启程", next = "act4_decide", flag = "feign_ok" },
}
}
S.act3_truth = {
chapter = "第三章 · 真相(1)",
title = "她的身世",
image = "scene_inn",
prose =
"我转过头,看着床上的穗。\n\n" ..
"『起来。』我说。\n\n" ..
"她坐起来,没说话。\n\n" ..
"我从怀里摸出三十两银子的凭条,放在桌上。\n\n" ..
"『这趟活儿,赵掌柜给了我三十两。』我说,『你叔父欠的债,也差不多这个数。』\n\n" ..
"她低着头,没反应。\n\n" ..
"『你叔父来了。刚才,就在外头坐着。』\n\n" ..
"她的肩膀抖了一下。\n\n" ..
"『他后悔了。他想带你走。』\n\n" ..
"她终于抬头了。\n\n" ..
"—— 我看见她眼睛里的东西,不是恨,不是怕,是一种比这两样都更深的东西。\n\n" ..
"『……是爹让叔父卖的我。』她说,声音很轻,『娘死了以后,爹就把我卖了。叔父也拦不住。』\n\n" ..
"我沉默了。\n\n" ..
"『—— 我不回去。』她说,『回去,还是要被卖的。』\n\n" ..
"我点头。\n\n" ..
"门外,那男人一直没有进来。",
choices = {
{ label = "让她自己决定:走还是留", next = "act4_decide", flag = "told_truth" },
}
}
S.act3_wait = {
chapter = "第三章 · 真相(2)",
title = "一夜未动",
image = "scene_inn",
prose =
"我没动,她也没动。\n\n" ..
"那男人在桌边坐到油灯燃尽,没再说一句话。\n\n" ..
"最后,只听见一声很轻的叹息。\n\n" ..
"他起身,在桌上放下了几块碎银——比他给我的多得多。\n\n" ..
"然后他走了。\n\n" ..
"—— 第二天我醒来的时候,那几块银子还在桌上。\n\n" ..
"穗比我先醒。\n\n" ..
"她蹲在桌边,看着那几块银子,看了很久。\n\n" ..
"她没拿。她站起身,把那几块银子推到我面前。\n\n" ..
"『—— 给您。』她说,『算路费。』\n\n" ..
"我看了她一眼,没接。我把银子收进我自己的包袱,她看了我一眼,没说话。\n\n" ..
"—— 后来我明白:她是想让我带她走。",
choices = {
{ label = "第二天启程", next = "act4_decide", flag = "silver_left" },
}
}
S.act3_expel = {
chapter = "第三章 · 真相(3)",
title = "逐客",
image = "scene_inn",
prose =
"我把他赶了出去。\n\n" ..
"门关上的一刻,我看见他眼睛里的光灭了。\n\n" ..
"夜里,门外一直没有动静。\n\n" ..
"可是到了后半夜,忽然听见房顶上有瓦片响。\n\n" ..
"—— 有人下来了。\n\n" ..
"我翻身坐起,把刀握在手里,低声对穗说:『别出声。』\n\n" ..
"她点了点头,把自己缩成一团,蹲在床角。\n\n" ..
"门闩被顶开。\n\n" ..
"—— 来的人不止一个。一个是那个同乡客,另一个,是个蒙面汉子,手里攥着短刀。",
choices = {
{ label = "拔刀迎敌", next = "act3_fight" },
{ label = "把穗压在身下,装睡", next = "act3_shield" },
}
}
S.act3_fight = {
chapter = "第三章 · 血夜",
title = "拔刀",
image = "scene_inn",
prose =
"我抄起枕边的朴刀,从床上翻身而起。\n\n" ..
"屋里很黑。油灯早就灭了。\n\n" ..
"我听见穗一声短促的惊叫,随即被自己捂住了嘴。\n\n" ..
"我挥刀——",
choices = {
{ label = "一刀劈下,结果了蒙面汉", next = "act3_kill", flag = "fought" },
{ label = "只削落他的刀,逼退二人", next = "act3_wound", flag = "spared" },
}
}
S.act3_shield = {
chapter = "第三章 · 血夜",
title = "挡在身下",
image = "scene_inn",
prose =
"我翻身把穗压在身下,被子盖住她。\n\n" ..
"一刀落下来,我左肩一凉——\n\n" ..
"—— 然后我听见朴刀出鞘的声响,是我自己的手替我拔的。\n\n" ..
"血从肩上流下来,热乎乎的。\n\n" ..
"我把刀反手一送,听见有人闷哼一声。\n\n" ..
"—— 然后一切都安静了。",
choices = {
{ label = "血战之后……", next = "act3_after_wounded", flag = "wounded" },
}
}
S.act3_kill = {
chapter = "第三章 · 血夜(1)",
title = "见血",
image = "scene_inn",
prose =
"那一刀快,我自己都没反应过来。\n\n" ..
"蒙面汉子倒下去的时候,血溅到了我脸上。\n\n" ..
"同乡客一声不吭,从后窗翻出去,跑了。\n\n" ..
"我喘着气。屋里全是血腥味。\n\n" ..
"穗缩在床角,一声不吭地看着地上的尸体。\n\n" ..
"—— 她的眼睛,在油灯的余烬里,亮得吓人。\n\n" ..
"我蹲下身,合上那汉子的眼皮。然后把刀在死人衣服上擦了擦,收回鞘。\n\n" ..
"—— 第二天,我和李掌柜一起把那具尸首埋在了后院枣树下。\n\n" ..
"没人问,没人说。",
choices = {
{ label = "天亮,继续上路", next = "act4_decide", flag = "fought" },
}
}
S.act3_wound = {
chapter = "第三章 · 血夜(2)",
title = "未下死手",
image = "scene_inn",
prose =
"我一刀削落了蒙面汉手里的短刀。\n\n" ..
"短刀在地上咣当一声。\n\n" ..
"他二人对视一眼,翻窗跑了。\n\n" ..
"我喘着气坐回床沿。左臂发麻,衣服上有一道口子,但没见血。\n\n" ..
"—— 穗第一次主动伸手,按在了我肩头。\n\n" ..
"她的手冰凉。\n\n" ..
"『……谢谢。』她说。\n\n" ..
"—— 这是她第一次对我说这两个字。\n\n" ..
"我没回答。我只是拍了拍她的头,像拍一个孩子。",
choices = {
{ label = "天亮,继续上路", next = "act4_decide", flag = "spared" },
}
}
S.act3_after_wounded = {
chapter = "第三章 · 血夜(3)",
title = "血醒",
image = "scene_inn",
prose =
"我醒来时,已经是第二天晌午。\n\n" ..
"伤口用布条缠着,缠得并不高明。\n\n" ..
"穗坐在床边,手里还拿着剩下的布条。\n\n" ..
"—— 她不会说话,可她救了我。\n\n" ..
"她见我醒了,把手里的水碗递给我。\n\n" ..
"我喝了几口,问她:『他人呢?』\n\n" ..
"她摇头。\n\n" ..
"—— 我知道,他们跑了。\n\n" ..
"我慢慢坐起来,左肩的伤口疼得我吸了一口凉气。\n\n" ..
"穗伸手扶了我一把。\n\n" ..
"—— 我忽然想:这孩子,不能再送到扬州了。",
choices = {
{ label = "谢过她,继续上路", next = "act4_decide", flag = "wounded" },
}
}
S.act4_decide = {
chapter = "第四章",
title = "汴梁城外 · 一条岔路",
image = "scene_yangzhou",
prose =
"过了中州,又走了几日。\n\n" ..
"到了汴梁(今开封)城外,已是腊月廿九。\n\n" ..
"城门口的官道上,人车稀少。年关将至,能回家的都回了家,回不了家的,就地缩在城外的破庙里熬着。\n\n" ..
"我站在一个三岔路口。\n\n" ..
"一条往东,三百里到扬州。按原计划,送到就拿尾款,事毕。\n\n" ..
"一条往南,二百里去汝州,再往西可以绕到南阳。\n\n" ..
"一条往西,回洛阳。\n\n" ..
"我看着身边这个瘦小的女孩子。\n\n" ..
"她没看我。她看着脚下的土,好像早就知道会有这一刻。\n\n" ..
"—— 我心里明白:这趟活儿,从头到尾就是个把孩子卖去扬州的活儿。\n\n" ..
"—— 她可能被卖去做妾,做婢,做下处。三十两银子,不是她的身价,是她的活命钱。\n\n" ..
"—— 可我若把她送回她叔父那里,她还是要被卖的。\n\n" ..
"我叹了口气。\n\n" ..
"风从北边吹来,带着雪的味道。",
choices = {
{ label = "按原计划,送她去扬州", next = "end_yangzhou_farewell" },
{ label = "给她留下银两,让她自己决定去留", next = "end_let_go" },
{ label = "不送她去扬州,带她走另一条路", next = "end_other_road" },
{ label = "回洛阳找她叔父,把人还给他", next = "end_find_uncle" },
}
}
S.end_yangzhou_farewell = {
chapter = "终章 · 扬州别离",
title = "扬州别离",
image = "scene_yangzhou",
prose =
"我还是把她送到了扬州。\n\n" ..
"一路上她没再说话。\n\n" ..
"到扬州时,正是除夕。烟雨江南,白墙黛瓦,运河两岸挂着红灯笼。\n\n" ..
"绸缎庄的接应人是个四十多岁的胖掌柜,验过文书,付了尾款。\n\n" ..
"走的时候,她回头看了我一眼。\n\n" ..
"没说话。\n\n" ..
"我朝她点了点头,转身出了门。\n\n" ..
"门在我身后合上的时候,我听见里头那胖掌柜说:『送到后院去,洗干净。』\n\n" ..
"—— 我停了脚步。\n\n" ..
"—— 我没回头。\n\n" ..
"我走出巷口,走上了回洛阳的官道。\n\n" ..
"三十里后,天降大雪。我坐在路边的一座破亭子里,喝完了那壶剩下的酒。\n\n" ..
"—— 后来我听说,扬州城数月后被流寇攻破,城里死了很多人。\n\n" ..
"—— 那孩子,再没人知道她的下落。\n\n" ..
"【 结局一 · 扬州别离 】\n\n" ..
"三十两银子,够一家老小过两年。\n\n" ..
"我心里,再也过不去。",
choices = {
{ label = "回到主菜单", next = "menu" },
}
}
S.end_let_go = {
chapter = "终章 · 留她独行",
title = "留她独行",
image = "scene_depart",
prose =
"我数出十两纹银,用布包好,放在她手里。\n\n" ..
"『前面三十里就是汴梁城。』我说,『你——自己看着办。』\n\n" ..
"她抬起头,看了我很久。\n\n" ..
"『……为什么?』\n\n" ..
"『因为这事我办不了。』我说。\n\n" ..
"我没等她回答。我转身走了。\n\n" ..
"—— 走了很久,我都没回头。\n\n" ..
"—— 我不敢回头。\n\n" ..
"我走出三里地,在路边一棵枯树下,站了很久。\n\n" ..
"后来我听说,在汴梁城里,有人见过一个瘦小的女孩,背着一只粗布包袱,朝着南边走。\n\n" ..
"再后来,就没人听说过了。\n\n" ..
"【 结局二 · 留她独行 】\n\n" ..
"我后来常常想:她到底去了哪里?她有没有活过那个冬天?\n\n" ..
"—— 我不知道。",
choices = {
{ label = "回到主菜单", next = "menu" },
}
}
S.end_other_road = {
chapter = "终章 · 复行数十步",
title = "复行数十步",
image = "scene_depart",
prose =
"我没去扬州。\n\n" ..
"我带她走了一条往南的旧路——去汝州,去南阳,去那种流寇都懒得去的小地方。\n\n" ..
"半路上,她开始愿意说话。\n\n" ..
"她说她叫穗。她说那一年发大水,她爹病死了,她娘也病死,叔父卖了她。\n\n" ..
"『……你恨他吗?』有一天我问她。\n\n" ..
"她想了很久,说:『不恨。我只是不明白。』\n\n" ..
"『为什么爹要卖我?』\n\n" ..
"我没回答。\n\n" ..
"—— 我也想不明白。\n\n" ..
"我们到了一个小镇,在城西租了一间小屋,开了个小小的车马店。\n\n" ..
"我管修车、喂马。她管做饭、洗碗。\n\n" ..
"她的眼睛,慢慢开始有光。\n\n" ..
"有一年除夕,她问我:『叔,您为什么救我?』\n\n" ..
"我想了很久,说:『—— 我也不知道。』\n\n" ..
"她笑了,我也笑了。\n\n" ..
"【 结局三 · 复行数十步 】\n\n" ..
"陶潜有诗:『既自以心为形役,奚惆怅而独悲?』\n\n" ..
"—— 有些路,走了就走了。",
choices = {
{ label = "回到主菜单", next = "menu" },
}
}
S.end_find_uncle = {
chapter = "终章 · 客死他乡",
title = "客死他乡",
image = "scene_river",
prose =
"我带着她,原路返回,去找她叔父。\n\n" ..
"—— 我想把人还给他,银子我也不要了,我就当没接过这活。\n\n" ..
"可走到孟津渡口的时候,天降大雪,路上不太平。\n\n" ..
"那夜,我们借宿在河滩边一座破庙里。\n\n" ..
"半夜里,庙外有动静。\n\n" ..
"—— 不是流民。\n\n" ..
"是一伙披着羊皮的人。\n\n" ..
"我挥刀。挥不动。一刀落空,又一刀落空。\n\n" ..
"他们人多。我只听得见穗在喊。\n\n" ..
"—— 后来,一切都没了。\n\n" ..
"我醒来时,天已经大亮。\n\n" ..
"我躺在雪地里,左肋有一道很深的伤口。\n\n" ..
"—— 穗,不在了。\n\n" ..
"—— 我没找见她。\n\n" ..
"我爬出破庙,走了三里地,倒在雪里。\n\n" ..
"—— 再也没起来。\n\n" ..
"【 结局四 · 客死他乡 】\n\n" ..
"我后来听人说,她被一个路过的人贩子带走了。\n\n" ..
"—— 也有人说,她自己走的。\n\n" ..
"—— 我都不信,也不愿再想。",
choices = {
{ label = "回到主菜单", next = "menu" },
}
}
-- ---------- 受控更新 ----------
local function asset_url(name)
local u = app.asset(name)
if u and u ~= "" then return u end
return "assets/" .. name
end
local function status_text()
local marks = {}
local order = {"soft", "warm", "spoke", "guard_on", "feign", "feign_ok",
"told_truth", "silver_left", "wounded", "fought", "spared"}
for _, k in ipairs(order) do
if state.flags[k] then
marks[#marks+1] = FLAG_NAME[k] or k
end
end
if #marks == 0 then return "📜 标记: (无)" end
return "📜 标记:" .. table.concat(marks, " · ")
end
local function goto_node(n)
state.node = n
save_state()
render()
end
local function click(i)
if state.node == "menu" then
if i == 1 then
local s = load_state()
if s and S[s.node] then goto_node(s.node) end
elseif i == 2 then
state.flags = {}
goto_node("prologue")
end
return
end
local node = S[state.node]
if not node or not node.choices then return end
local c = node.choices[i]
if not c then return end
if c.flag then state.flags[c.flag] = true end
goto_node(c.next)
end
function render()
if state.node == "menu" then
app.set_text("chapter_title", "")
app.set_visible("chapter_title", false)
app.set_image("scene_img", asset_url("icon.webp"))
app.set_visible("scene_img", true)
app.set_text("prose",
"明末崇祯六年(1633),腊月。\n\n" ..
"我,良爷,一个做了十多年脚夫的中年汉子。\n" ..
"今日接了一单私活:护送一位『亲眷女孩』,从洛阳送往扬州。\n\n" ..
"三十两纹银。\n" ..
"千里路程。\n\n" ..
"—— 这趟活,说不上凶险,却也说不上干净。")
app.set_text("status", "")
app.set_visible("status", false)
local s = load_state()
if s and S[s.node] then
app.set_text("c1", "▶ 继续上次剧情(【" .. S[s.node].chapter .. "】)")
app.set_visible("c1", true)
else
app.set_visible("c1", false)
end
app.set_text("c2", "▶ 开始新游戏")
app.set_visible("c2", true)
app.set_visible("c3", false)
app.set_visible("c4", false)
app.set_visible("menu_btn", false)
return
end
local node = S[state.node]
if not node then
state.node = "menu"
save_state()
return render()
end
app.set_text("chapter_title", "【" .. node.chapter .. "】" .. node.title)
app.set_visible("chapter_title", true)
if node.image then
app.set_image("scene_img", asset_url(node.image .. ".webp"))
app.set_visible("scene_img", true)
else
app.set_visible("scene_img", false)
end
app.set_text("prose", node.prose)
app.set_text("status", status_text())
app.set_visible("status", true)
for i = 1, 4 do
local btn = "c" .. i
local c = node.choices and node.choices[i]
if c then
app.set_text(btn, "「" .. c.label .. "」")
app.set_visible(btn, true)
else
app.set_visible(btn, false)
end
end
app.set_visible("menu_btn", true)
end
-- ---------- 静态 page(顶层) ----------
local page = ui.page({
title = "饿殍:明末千里行",
children = {
ui.text({
id = "chapter_title",
text = "",
size = 17,
color = "#6FACC9",
margin = 6,
}),
ui.image({
id = "scene_img",
url = asset_url("icon.webp"),
height = 180,
margin = 4,
}),
ui.text({
id = "prose",
text = "加载中……",
size = 15,
margin = 6,
}),
ui.text({
id = "status",
text = "",
size = 12,
color = "#888888",
margin = 4,
}),
ui.spacer({ height = 6 }),
ui.button({ id = "c1", text = "", margin = 4, on_click = function() click(1) end }),
ui.button({ id = "c2", text = "", margin = 4, on_click = function() click(2) end }),
ui.button({ id = "c3", text = "", margin = 4, on_click = function() click(3) end }),
ui.button({ id = "c4", text = "", margin = 4, on_click = function() click(4) end }),
ui.spacer({ height = 8 }),
ui.button({
id = "menu_btn",
text = "↩ 返回主菜单",
margin = 4,
on_click = function() goto_node("menu") end,
}),
}
})
-- 触发首次渲染
render()
return page