Cataclysm-DDA Megacity Mod 设计蓝图解读:无限都市的生成机制与生存压力设计
【免费下载链接】Cataclysm-DDACataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.项目地址: https://gitcode.com/GitHub_Trending/ca/Cataclysm-DDA
导读
Megacity 是 Cataclysm-DDA(大灾变:黑暗之日)官方仓库中的一个"全城市"总转换(total_conversion)模组:整个世界被一座没有尽头的巨型城市覆盖,没有原野、森林与河流,玩家从避难所(Evac Shelter)出发后,等待他的只有"钢与混凝土的地狱"。本文以模组作者 Renech 在 data/mods/Megacity/TODO.md 中留下的开发规划为主线,结合 data/mods/Megacity/modinfo.json 的实际配置与 src/overmap_city.cpp、src/regional_settings.cpp、src/overmap_worldgen.cpp 等源码实现,逐条拆解这个模组"如何造出一座无限都市",以及"如何让玩家被困在这座都市里"的设计思路,读完你可以理解 CDDA 区域生成(region settings)与超大地图(overmap)城市铺设机制的底层原理,并看清该模组已实现与待开发的功能边界。
一、模组定位:一个"没有出口"的世界
modinfo.json中对模组的描述是:
The president's dead and the city stretches on. Whether you walk for 24 hours or 24 days, there is only more city. There is no escape from this steel and concrete hell.
(总统已死,城市无尽延伸。无论你走 24 小时还是 24 天,前方只有更多的城市。在这钢与混凝土的地狱中,无处可逃。)
这段描述与 TODO 中"这不是'阈限空间'(liminal space),只是一座足够大的、近乎无限的城市,刻意不给任何超自然解释"的定位完全一致——模组坚持用纯粹的地图生成逻辑而非魔法设定来制造"囚笼感"。
在模组目录中,Megacity 的全部内容只有两个文件:modinfo.json 与 TODO.md,没有新增任何建筑、物品或怪物 JSON。这意味着整个模组完全依靠覆写(copy-from)原版默认区域设置来改变世界形态,是一个"配置驱动"的模组范例。
其MOD_INFO声明了关键信息:
category: "total_conversion"——总转换类模组,会彻底改变世界生成形态;dependencies: ["dda"]——依赖原版基础模组;conflicts——与aftershock_exoplanet、backrooms、tropicata、classic_zombies、Isolation_Protocol、innawood、no_hope等模组冲突,这些模组同样会替换区域/地形生成逻辑,二者无法共存。
二、无限都市是如何生成的:modinfo.json 三层结构拆解
Megacity 的世界生成由modinfo.json中三段相互关联的 JSON 结构驱动,对应 CDDA 世界生成的三层抽象:维度(dimension)→ 区域布局(region layout)→ 区域设置(region settings)。
2.1 维度与区域布局:整个世界只有一种区域
{ "type": "dimension", "id": "Default", "region_layout": "default" }, { "type": "dimension_region_layout", "id": "default", "generation_mode": "UNIFORM", "uniform_region": "mega_mega_city" }- 第一个对象把默认维度
Default的区域布局(region_layout)指定为default; - 第二个对象定义了该布局的生成方式:
generation_mode: "UNIFORM",即整个世界地图统一使用mega_mega_city这一个区域设置。
从源码 src/overmap_worldgen.h 可以看到,regions_generation_mode目前支持四种模式:
| 模式 | 说明 |
|---|---|
UNIFORM | 动态生成;整个维度只有一个区域 |
MANUAL_VORONOI | 静态生成;用 JSON 布置区域点,再由 Voronoi 图划分区域 |
RANDOM | 动态生成;每张 overmap 从区域集合中随机挑选 |
ANGLES | 动态生成;把世界地图按角度等分成扇形区域 |
对应实现dimension_region_layout_generator_uniform::generate_dynamic只有一行核心逻辑(见 src/overmap_worldgen.cpp):placed_regions.emplace( current_om, uniform_region )——无论请求哪张 overmap,都返回同一个区域mega_mega_city。这就是"走到天涯海角也只有城市"的机制基础。
2.2 区域设置:抹掉一切非城市地形
{ "type": "region_settings", "id": "mega_mega_city", "copy-from": "default", "place_swamps": false, "rivers": null, "ocean": null, "forests": null, "lakes": null, "highways": null, "cities": "mega_mega_city_settings", "feature_flag_settings": { "extend": { "whitelist": [ "FAKE_UNUSED_FLAG" ] } } }这段配置以copy-from: "default"继承原版默认区域设置,然后逐一覆写:
place_swamps: false——不生成沼泽;rivers、ocean、forests、lakes、highways全部设为null——从世界生成管线中移除河流、海洋、森林、湖泊与高速公路。这直接落实了 TODO 中"每个格子都被填满,零原野、零森林、零非城市建筑"的目标;同时"没有河流"也是 TODO 中"口渴压力可能更有效"这一设计的前提;cities指向自定义的城市设置mega_mega_city_settings。
在 src/regional_settings.cpp 的region_settings::load中可以看到,forests、rivers、lakes、ocean、highways等字段都以optional(...)方式解析,值为null时对应可选区域不会生效,从而被整体跳过生成。
2.3 城市设置:无限都市的核心参数
{ "type": "region_settings_city", "id": "mega_mega_city_settings", "copy-from": "default", "is_megacity": true, "city_size": 16, "city_spacing": 0, "shop_radius": 200, "shop_sigma": 0, "park_radius": 0, "park_sigma": 0 }对照 src/regional_settings.h 中region_settings_city的结构体默认值,可以清楚地看出每个参数的用意:
| 参数 | 原版默认值 | Megacity 值 | 含义 |
|---|---|---|---|
is_megacity | false | true | 开启"巨型都市"专用铺设逻辑 |
city_size | 8 | 16 | 城市基准半径(overmap 格子数),并作为 megacity 分支的判定输入 |
city_spacing | 4 | 0 | 城市间距;0 意味着城市彼此紧贴,地图覆盖率接近 100% |
shop_radius | 30 | 200 | 商铺区相对市中心的分布半径 |
shop_sigma | 20 | 0 | 商铺区分布的正态标准差;0 时取消随机波动 |
park_radius | = shop_radius | 0 | 公园分布半径;0 表示市中心无公园 |
park_sigma | = 100 - shop_radius | 0 | 公园分布标准差;0 时公园完全消失 |
关于city_spacing: 0:src/overmap_city.cpp 的注释给出了一张"城市间距 × 城市大小 → 每张 overmap 城市数量"的对照表:当city_spacing = 0、city_size = 16时,单张 overmap 上会生成约 31 个城市,地图覆盖率约 99%——这就是"零空隙"城市的空间基础。
三、源码级的巨型都市铺设:is_megacity 分支
TODO 的第 1 条写道:"需要更好的城市放置方式,让城市真正重叠、每个格子都被填满,零原野、零森林、零非城市建筑。"而当前实现是通过is_megacity分支完成的。
在 src/overmap_city.cpp 的overmap::place_cities()中,当city_settings.is_megacity为真时,走的是完全独立于常规城市随机铺设的代码路径:
- 把每张 overmap(尺寸为
OMAPX × OMAPY)按四等分取点,得到 4 个等距的"象限城市"锚点{OMAPX/4, OMAPY/4}、{OMAPX/4, OMAPY*3/4}、{OMAPX*3/4, OMAPY/4}、{OMAPX*3/4, OMAPY*3/4},再补上正中央的{OMAPX/2, OMAPY/2}作为第 5 个锚点; - 每个锚点先用
ter_set( selected_point, oter_road_nesw )铺设一条十字路口作为城市起点,并登记进city_tiles; - 每座城市的
tmp.size = 40——代码注释明确指出"数值越大填充越满,但性能会因城市相互叠加铺设而急剧恶化,40 是当前能保持可玩性的取值"; - 5 个锚点各自生长出的城市在 overmap 上互相重叠、填满整张地图,随后由
flood_fill_city_tiles()(src/overmap_city.cpp)把被城市包围的非城市区域也并入city_tiles。
这正是 TODO 中所说"城市彼此重叠、每格都被填满"的当前实现方式;TODO 也坦诚地记录了它的缺陷——目前只是"以牺牲性能为代价的近似方案",未来希望找到"真正的、可负担的完全填充算法"。
四、TODO 路线图逐条解读:从"无尽城市"到"求生压力"
TODO.md 本质上是作者对未来开发方向的清单。以下逐条结合源码说明其意图与实现现状。
4.1 商业区与郊区的再平衡(TODO 第 2 条)
需要更好地处理"商业区"与"郊区"的关系。目前郊区过于庞大;我想要被大片高层与商业建筑包围的小块郊区。更新:我已让郊区消失,但这好坏参半,需要调整 sigma 值,让城市中极偶尔地出现小块郊区。
这条 TODO 直接对应shop_radius、shop_sigma、park_radius、park_sigma四个参数。在 src/overmap_city.cpp 的overmap::pick_random_building_to_place()中:
int shop_normal = shop_radius; if( shop_sigma > 0 ) { shop_normal = std::max( shop_normal, static_cast<int>( normal_roll( shop_radius, shop_sigma ) ) ); }其逻辑是:用normal_roll(shop_radius, shop_sigma)做一次正态分布抽样,得到本城的"商业延伸距离"shop_normal;当某建筑位置到市中心的归一化距离town_dist < shop_normal时放商铺,< park_normal时放公园,否则放住宅。当前模组把shop_radius拉到 200、shop_sigma设为 0,意味着全城范围都按商业区处理(town_dist的取值区间由trig_dist(...) * 100 / max(town.size, 1)决定,见 src/overmap_city.cpp,其上限不会超过 100,因此 200 的半径实际上覆盖全城)——这就是"郊区已全部消失"的机制原因。TODO 提出的下一步是给shop_sigma一个很小的正值,让正态分布偶尔抽到较小的shop_normal,从而在极小概率下"漏出"一小块住宅/郊区地带。
4.2 逼迫玩家持续迁徙的"鞭子"(TODO 第 3 条)
需要某种"鞭子"迫使玩家不断向城市中未探索的新区域迁徙。被困在无尽城市里,只有当你真的被困住时才有意思。如果你杀光了方圆一英里内的所有东西,然后翘着脚坐着,那就毫无意义了。可能的手段:完全禁用农业;食物压力肯定是一种方式。口渴压力可能更有效,因为这里没有河流。
这条设计意图是 Megacity 的核心生存哲学:无限都市不是"末日乐园",而是资源枯竭的监狱。TODO 明确表示这不是寻找"魔法或异世界解释",而是纯粹通过资源稀缺制造张力,并且刻意不给任何解释。从配置现状看,目前模组尚未实现农业禁用与食物/水资源压力(modinfo.json 中没有相关覆写),属于明确的"待办"范畴。
4.3 移除一切无限水源(TODO 第 4 条)
移除任何无限水源(以增强口渴压力)。包括后院泳池、带水格的公园等。这不包括单纯的净水。
这条同样处于"规划中"状态。其目标是配合 4.2,让水成为玩家持续向外推进的硬性驱动——因为 TOD/rivers: null已确保地图上没有河流,天然水源一旦被清空,玩家就必须不断向城市深处探索寻找新的供水点。
4.4 更混乱的城市与路障(TODO 第 5 条)
更混乱的城市、街道上的路障等,目的是让载具旅行刻意变得困难。这大概可以直接进入原版 DDA,所以先提交到那里。
TODO 作者在此给出了明确的贡献建议:这类"城市混乱化"改动(街道路障、残骸等)并不局限于 Megacity 模组,适合直接作为 PR 提交给原版游戏(vanilla DDA),让所有玩家受益。这也呼应了仓库 CONTRIBUTING.md 中常规的开源贡献流程。
五、配套设置:避难所起点与场景黑名单
为了让玩家在纯城市世界中有一个合法出生点,modinfo.json还做了两处配套处理:
{ "id": "FAKE_UNUSED_FLAG", "type": "json_flag", "name": "", "//COMMENT": "Fake flag used for an empty whitelist." }, { "type": "overmap_special", "id": "Evac Shelter", "copy-from": "Evac Shelter", "//COMMENT": "Oops! Not so unused now, are you? Well we need to spawn somewhere, so this will have to do. For now.", "extend": { "flags": [ "FAKE_UNUSED_FLAG" ] } }, { "type": "SCENARIO_BLACKLIST", "subtype": "whitelist", "scenarios": [ "evacuee" ] }- 定义了一个空 flag
FAKE_UNUSED_FLAG,把它加入区域设置的feature_flag_settings.whitelist——因为当前区域没有其他可选地物,需要用这个"空白名单"维持特征系统的合法性; - 用
copy-from扩展原版 "Evac Shelter"(避难所)这个 overmap 特殊建筑并打上该 flag,保证它能在巨型都市中被生成,成为玩家唯一的出生/庇护点; - 用
SCENARIO_BLACKLIST的whitelist子类型把出生场景锁定为 "evacuee"(避难者),避免其他场景引用不存在的出生地形导致生成失败。
作者在注释里也承认这是"暂时的权宜之计"("Well we need to spawn somewhere, so this will have to do. For now."),未来会替换成更正式的出生方案。
六、如何体验 Megacity 模组
Megacity 已内置在 Cataclysm-DDA 仓库的 data/mods/Megacity 目录中,无需单独下载。安装与体验方式如下:
- 从当前仓库构建游戏(参见仓库根目录 README.md 的构建说明,Linux 下通常执行
make或使用 CMake,构建产物为cataclysm-tiles等); - 启动游戏,进入"新世界/New World"创建界面;
- 在模组(Mods)列表中勾选Megacity(分类为 total_conversion,属于"世界形态替换"类模组);
- 选择 "evacuee"(避难者)场景开始游戏;
- 进入世界后你会发现:地图上没有任何森林、河流、湖泊与高速公路,只有连绵不绝的城市街区,你可以通过调试菜单(Debug Menu)观察 overmap 上
city_tiles的覆盖情况,验证"每个格子都是城市"的生成效果。
需要注意:由于它是总转换模组,且与多个替换世界地形的模组存在conflicts声明,请勿与其他冲突模组同时启用;城市生成采用 5 锚点重叠铺设,在低性能机器上首次生成世界时可能较慢(源码注释已提示性能随填充度恶化)。
七、结语:一份"活着的"设计文档
Megacity 的 TODO.md 与绝大多数项目文档不同——它不是使用说明,而是一份作者公开的开发路线图与设计哲学声明:从"城市完全填充"到"商业区/郊区再平衡",从"禁农业、缺水"的资源压力设计,到"路障化城市"的原版化建议,每条都直接映射到 modinfo.json 的具体参数与 src/overmap_city.cpp 等源码分支。它也诚实标注了哪些想法已经实现(如 sigma 归零消除郊区)、哪些仍待解决(如真正的完全填充算法、农业禁用、水源清理)。
对模组作者而言,这份文档示范了"先定玩法目标、再落实到区域参数、最后反馈到源码机制"的设计闭环;对 CDDA 玩家而言,理解这些参数,就等于掌握了 region_settings 系统中"如何用一份 JSON 重塑整个世界"的能力。
【免费下载链接】Cataclysm-DDACataclysm - Dark Days Ahead. A turn-based survival game set in a post-apocalyptic world.项目地址: https://gitcode.com/GitHub_Trending/ca/Cataclysm-DDA
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考