news 2026/9/15 18:20:43

Cataclysm-DDA 地形变换系统完全指南:深入解析 ter_furn_transform JSON 对象

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Cataclysm-DDA 地形变换系统完全指南:深入解析 ter_furn_transform JSON 对象

Cataclysm-DDA 地形变换系统完全指南:深入解析 ter_furn_transform 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

ter_furn_transform 是《大灾变:黑暗降临》(Cataclysm-DDA)中用于将地图上的"格"(tile)从一种类型变换为另一种类型的 JSON 对象,可作用于 field(场)、furniture(家具)、terrain(地形)与 trap(陷阱)四类地图元素。本文将以 doc/JSON/TER_FURN_TRANSFORM.md 为骨架,结合src/magic_ter_fur_transform.cppsrc/magic_ter_furn_transform.h的源码实现与data/mods/Magiclysm/ter_fur_transform/下的真实数据,系统讲解该对象的完整语法、加权随机、flag 匹配、消息提示机制,以及如何在 effect on conditions(EoC)、mapgen 与法术中调用它。读完本文,你将能独立编写、调试并复用地形变换定义,为魔法、陷阱、事件触发等模组功能提供可靠的地图变换能力。

一、什么是 ter_furn_transform

ter_furn_transform是一种 JSON 数据对象类型,它允许你指定一个"格"从一种类型变换为另一种类型。这里"格"(tile)指代的是地图上的四类元素之一:field(场)furniture(家具)terrain(地形)trap(陷阱)

从源码角度看,该对象由src/magic_ter_fur_transform.cpp中的generic_factory<ter_furn_transform>工厂管理(magic_ter_fur_transform.cpp),它继承自模板类ter_furn_data<T>,其中T可以是ter_str_idfurn_str_idtrap_str_idfield_type_id之一(见 magic_ter_furn_transform.h)。这意味着同一套变换语法被统一抽象,四类元素共用一套"结果 + 权重 + 消息"的数据模型。

一个最基础的示例:

[ { "type": "ter_furn_transform", "id": "example", "terrain": [ { "result": "t_dirt", "valid_terrain": [ "t_sand" ], "message": "sandy!", "message_good": true } ] } ]

上面的例子将地形t_sand(沙子)变换为t_dirt(泥土)。它是通过直接比较地形 ID 实现的——当变换被触发时,系统读取目标格的当前地形 ID,与valid_terrain列表中的 ID 逐一匹配。

二、核心语法:result 与 valid_* 列表

2.1 单一结果

每个变换条目由两个核心字段组成:

  • result:变换的目标类型 ID(或 ID 列表/加权列表),支持terrainfurniturefieldtrap四类对应的 ID 前缀(t_f_fd_tr_)。
  • valid_*:触发条件的源类型 ID 列表,分别为valid_terrainvalid_furniturevalid_fieldvalid_trap

源码中的加载逻辑证实了这一点:在 magic_ter_fur_transform.cpp 中,terrainfurniturefieldtrap四个成员分别被遍历,并把valid_terrainvalid_furniturevalid_fieldvalid_trap数组中的每个 ID 映射到同一个ter_furn_data结果对象(使用std::map::emplace存入对应的变换表)。

2.2 多个结果与随机选择

如果希望沙子变换为"泥土或草地",可以把result写成 ID 数组:

"terrain": [ { "result": [ "t_dirt", "t_grass" ], "valid_terrain": [ "t_sand" ], "message": "sandy!" } ]

message_good是可选的,默认值为true(源码中通过jo.get_bool( "message_good", true )读取,见 magic_ter_fur_transform.cpp)。上面的例子在泥土与草地之间以1:1 比例随机选择,即两者各有 50% 概率。

2.3 加权随机结果

1:1 的随机比例可以通过加权调整为任意比例,例如 4:1:

"terrain": [ { "result": [ [ "t_dirt", 4 ], "t_grass" ], "valid_terrain": [ "t_sand" ], "message": "sandy!" } ]

语法要点如下:

  • 数组中每一项可以是单个字符串(隐式权重为 1),也可以是[ "id", 权重 ]形式的嵌套数组;
  • 两种写法可以混合使用
  • 实际抽取时,系统会依据权重做加权随机。实现上,weighted_int_list<T>是权重列表的核心容器,其pick()方法负责完成加权抽样,最终由ter_furn_data<T>::pick()返回被选中的 ID(见 magic_ter_fur_transform.cpp);
  • result是单个字符串时,源码load_transform_results会直接以权重 1 将其加入列表(magic_ter_fur_transform.cpp),这与文档中"每个单字符串权重为 1"的描述完全一致。

2.4 四类元素通用

以上所有语法同样适用于fieldsfurnituretraps。例如:

"field": [ { "result": "fd_null", "valid_field": [ "fd_fire" ], "message": "The fires suddenly vanishes!", "message_good": true } ], "furniture": [ { "result": [ [ "f_null", 4 ], "f_chair" ], "valid_furniture": [ "f_hay", "f_woodchips" ], "message": "I need a chair" } ]

值得注意的是,result可以是空类型 ID(如fd_nullf_nullt_nulltr_null),这意味着该变换可以用于移除对应的场、家具、地形或陷阱。

2.5 使用 flag 而非 ID 匹配

除了精确 ID 匹配,furnitureterraintrap三类还支持用**flag(标志位)**进行匹配:

"terrain": [ { "result": "t_dirt", "valid_flags": [ "DIGGABLE" ], "message": "digdug" } ]

valid_flags列表中的每个 flag 会与目标地形/家具/陷阱实际拥有的 flag 进行比对。从源码结构看,flag 匹配与 ID 匹配被存储在不同的表中:ter_flag_transformfurn_flag_transformtrap_flag_transform分别对应三类元素的 flag 变换表(magic_ter_furn_transform.h)。需要注意的是,field 不支持 flag 匹配——源码中 field 只有field_transform一张按field_type_id精确匹配的表。

匹配的优先级逻辑在transform()中体现:系统先尝试精确 ID 匹配,只有当 ID 匹配失败时,才遍历 flag 变换表,调用has_flag()检查目标是否携带该 flag(magic_ter_fur_transform.cpp)。例如对于地形:先查ter_transform中是否有t_sand这样的精确条目;若无命中,再遍历ter_flag_transform,检查当前地形是否带有DIGGABLE等 flag,命中即停止。

三、字段独立性:四类变换互不干扰

一个ter_furn_transform可以同时包含fieldfurnitureterraintrap四个字段。但它们彼此独立处理——不存在"如果沙子变成泥土,就顺便把椅子放上去"这样的联动逻辑。

源码中,transform( map &m, const tripoint_bub_ms &location )会分别查询并处理四类元素(magic_ter_fur_transform.cpp):

  1. 读取目标格当前的地形m.ter()、家具m.furn()、陷阱m.maptile_at().get_trap()与场m.field_at()
  2. 依次为每类元素寻找可用的变换结果;
  3. 独立执行设置:m.ter_set()m.furn_set()m.trap_set(),场则先m.add_field()新场再m.remove_field()旧场,且保留原有的场强度(intensity)与年龄(age)
  4. 四类结果之间没有任何依赖或联动关系。

对于场还有一个细节:一个格上可能存在多个场(如同时有烟雾与火焰),transform()会遍历该格的所有场,逐个尝试匹配并变换。

四、消息提示机制

每个变换条目都可以配置message(消息文本)与message_good(消息好坏标记):

  • message:当变换成功且玩家能看到该格时显示的消息。源码中,只有you.sees( m, location )为真且消息非空时才会输出,并通过add_msg_if_player发送给玩家(magic_ter_fur_transform.cpp);
  • message_good:可选,默认true。为true时消息以正面颜色(m_good)显示,为false时以负面颜色(m_bad)显示。例如"The fires suddenly vanishes!"可以标记为message_good: true,而危险的陷阱触发则适合false

这一机制让模组作者可以即时向玩家反馈变换结果,例如施法时显示"大地为你让路",或陷阱触发时警告玩家。

五、如何调用 ter_furn_transform

ter_furn_transform本身只是一份数据定义,它需要通过以下三种途径之一被实际触发。

5.1 在 effect on conditions(EoC)中使用

EoC 提供了两种相关效果,详细语法见 doc/JSON/EFFECT_ON_CONDITION.md:

u_transform_radius/npc_transform_radius:以玩家(u)、NPC(npc)或指定目标为中心,在半径范围内执行变换。

字段必填说明
"u_transform_radius" / "npc_transform_radius"int 或变量对象变换发生的半径范围
"ter_furn_transform"string 或变量对象使用的 ter_furn_transform 的 id
"target_var"变量对象若指定,则使用变量中的目标位置代替玩家当前位置
"time_in_future"int/时长/变量对象/区间延迟变换发生的时间;可用 "infinity" 使位置一直不更新,直到key事件发生
"key"string 或变量对象外部可触发的事件 id,需配合 alter_timed_events 使用

示例一:将玩家周围 5 格内的地图元素按merc_spike_transform变换:

{ "u_transform_radius": 5, "ter_furn_transform": "merc_spike_transform" }

示例二:在 2~10 秒后(或收到detonator事件时),将变量door_transform指向的位置周围 2 格按detonate_the_door变换:

{ "u_transform_radius": 2, "ter_furn_transform": "detonate_the_door", "target_var": { "global_val": "door_transform" }, "time_in_future": [ "2 seconds", "10 seconds" ], "key": "detonator" }

transform_line:在两点之间画一条直线,并沿线逐格执行变换,常用于血迹、烧焦痕迹等轨迹效果(doc/JSON/EFFECT_ON_CONDITION.md)。

字段必填说明
"transform_line"string 或变量对象使用的 ter_furn_transform 的 id
"first", "second"变量对象u_location_variable创建的两个坐标点,直线在二者之间
{ "transform_line": "blood_trail", "first": { "global_val": "point_0" }, "second": { "global_val": "point_1" } }

5.2 在 mapgen 中使用

mapgen 中的ter_furn_transforms功能允许在指定的位置运行变换,可改变已生成的场、家具、地形或陷阱(包括置为空类型)。语法见 doc/JSON/MAPGEN.md:

  • transform(必填,string):要运行的ter_furn_transform的 id;
  • place_ter_furn_transforms(配合 x/y):指定坐标执行变换,xy可以是整数或[ min, max ]数组——若其中之一或两者是数组,则对该范围内的所有位置应用变换。

这使地形变换可以嵌入到建筑、区域或生物群落的生成流程中,例如生成岩浆湖时把范围内的地面统一变为岩浆地形。

5.3 在法术(spells)中使用

ter_furn_transform也可以作为法术效果使用。在 magic_spell_effect.cpp 中,法术通过sp.effect_data()读取变换 id,再将其转换为ter_furn_transform_id执行。法术效果(spell effects)的完整列表见 doc/JSON/MAGIC.md。这让法术能够"改造地形"——例如魔法流派 Mod Magiclysm 中的大地系法术。

六、真实案例:Magiclysm 中的 move_earth

仓库自带的 Magiclysm 魔法流派 Mod 提供了大量真实可用的ter_furn_transform定义,位于 data/mods/Magiclysm/ter_fur_transform/ter_fur_transform.json。以move_earth(移土术)为例,它演示了如何用一个变换定义完成多层地形递进:

{ "type": "ter_furn_transform", "id": "move_earth", "terrain": [ { "result": "t_open_air", "valid_terrain": [ "t_pit", "t_slope_down" ], "message": "The pit has deepened further." }, { "result": "t_pit", "valid_terrain": [ "t_pit_corpsed", "t_pit_covered", "t_pit_glass", "t_pit_spiked", "t_rootcellar", "t_pit_shallow" ], "message": "More debris shifts out of the pit." }, { "result": "t_pit_shallow", "valid_terrain": [ "t_grave", "t_dirt", "t_sand", "t_clay", "t_dirtmound", "t_grass", "t_dirtfloor", "t_sandbox" ], "message": "The earth moves out of the way for you." }, { "result": "t_sand", "valid_terrain": [ "t_pavement", "t_sidewalk", "t_concrete", "t_floor", "t_carpet_red", "t_linoleum_white", "t_slope_up", "t_rock_red" ], "message": "The rocks here are ground into sand." } ] }

这个案例展示了三种实战技巧:

  1. 多条目并行:同一个变换可以包含多个 terrain 条目,每个条目对应一组不同的源地形和目标结果;
  2. 分类归纳:通过枚举大量相关地形 ID(各种坑、各种地面、各种岩石)实现"对整类地形生效";
  3. 消息差异化:每种变换都有独立的提示消息,如"The pit has deepened further.",配合默认message_good: true显示为正面反馈。

类似的真实定义还存在于 data/mods/Magiclysm/ter_fur_transform/death_effects.json、data/mods/BombasticPerks/perkdata/perk_regions_and_mapgen/Closetland.json、data/mods/Isolation-Protocol/EOC/bossfight_mode.json 以及 data/mods/MindOverMatter/ter_transform/ter_transform.json 等文件中;测试数据见 data/mods/TEST_DATA/effect_on_condition.json 与 data/mods/TEST_DATA/magic.json。

七、编写与调试要点总结

  • ID 前缀约定:地形用t_前缀(如t_dirt)、家具用f_(如f_chair)、场用fd_(如fd_fire)、陷阱用tr_。使用不存在的 ID 会在加载时报错;
  • result 可以是空 IDfd_nullf_nullt_nulltr_null用于移除对应元素,是实现"灭火""拆家具""填坑"的标准做法;
  • 权重语法"result": [ "a", [ "b", 4 ] ]表示 a 权重 1、b 权重 4;单字符串隐式权重为 1;
  • ID 匹配优先于 flag 匹配valid_*valid_flags可以共存于同一个变换(terrain/furniture/trap支持 flags,field 不支持);
  • 消息可选但建议提供:没有message时玩家不会收到任何提示(源码中消息为空则跳过输出),但变换本身照常执行;
  • 四类元素独立:需要"同时改变地形与家具"时,在同一个变换中分别写terrainfurniture条目即可,系统会分别处理。

以上要点均可在源码 src/magic_ter_fur_transform.cpp 与 src/magic_ter_furn_transform.h 中逐行验证。掌握 ter_furn_transform 之后,你便可以在事件、地图生成与法术系统中自由地塑造世界——无论是法师的移山填海,还是陷阱房的门户变幻,都只是几行 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 18:20:12

CSS if()函数:原生条件计算与暗色模式实践指南

1. 这不是“CSS 写 if”&#xff0c;而是 CSS 终于拥有了条件计算能力2026 年初&#xff0c;Chrome 137 正式发布后&#xff0c;前端圈炸了锅。朋友圈、技术群、掘金热榜反复刷屏一句话&#xff1a;“2026年了&#xff0c;CSS 终于能写 if 了”。我第一时间打开 DevTools&#…

作者头像 李华
网站建设 2026/9/15 18:20:00

4 步完成抖音无水印下载:douyin-downloader 新手实操指南

4 步完成抖音无水印下载&#xff1a;douyin-downloader 新手实操指南 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback su…

作者头像 李华
网站建设 2026/9/15 18:19:29

SpringBoot外卖跑腿系统:智能调度与高并发实践

1. 项目概述与背景外卖跑腿配送系统是近年来随着本地生活服务数字化浪潮兴起的关键基础设施。我们团队基于SpringBoot框架开发的这套系统&#xff0c;核心解决了三个行业痛点&#xff1a;订单流转效率低、配送资源调度不均衡、商户与骑手协同困难。在实测中&#xff0c;相比传统…

作者头像 李华
网站建设 2026/9/15 18:19:18

基于MAX V 5M570的CPLD实现I2C RTC(PCF8563)驱动设计

简介&#xff1a;面向CPLD/FPGA开发者和硬件设计学习者&#xff0c;这套MAXV 5M570 CPLD开发板原理图与PCF8563高精度温补RTC芯片的Verilog驱动源码&#xff0c;以完整的Quartus 13.0工程形式提供&#xff0c;可直接打开分析或二次开发。核心模块pcf8563以mclk和reset作为输入&…

作者头像 李华
网站建设 2026/9/15 18:19:08

高压直流输电在线监测系统的Matlab仿真与工程实践

1. 高压直流输电在线监测系统的工程价值在电力系统现代化进程中&#xff0c;高压直流输电&#xff08;HVDC&#xff09;技术因其远距离大容量输电的经济性&#xff0c;已成为跨区域电网互联的核心手段。但直流输电线路的绝缘子污闪、换流阀过热等故障具有突发性强、破坏性大的特…

作者头像 李华
网站建设 2026/9/15 18:18:08

OpenHarmony中List列表组件的分布式优化与应用

1. List列表组件在OpenHarmony应用开发中的核心价值作为React Native&#xff08;RN&#xff09;开发者在OpenHarmony生态中的高频组件&#xff0c;List列表承载着90%以上的数据展示场景。不同于传统移动端开发&#xff0c;OpenHarmony的分布式特性给列表组件带来了新的技术挑战…

作者头像 李华