附录:语法参考
附录:语法参考
总览
本文档是编写 CWT 规则文件和 Paradox 模组时所涉及的领域特定语言的语法参考。 文档内容基于 Paradox Chronicle 插件的解析实现编写,在绝大多数情况下与游戏引擎的实际行为一致,但由于游戏引擎的解析细节并非完全公开,个别边界情况可能存在差异。
本文档涵盖以下四种语言:
- CWT(
*.cwt) - 用于编写 CWT 规则文件。支持行注释#、选项注释##和文档注释###。代码块语言 ID:cwt。 - Paradox Script(
*.txt、*.gfx、*.gui等) - 用于编写游戏脚本。支持行注释#。代码块语言 ID:paradox_script。 - Paradox Localisation(
*.yml) - 用于编写本地化文本。支持行注释#。代码块语言 ID:paradox_localisation。 - Paradox CSV(
*.csv) - 分号分隔的 CSV 格式。支持行注释#。代码块语言 ID:paradox_csv。
其中,CWT 与 Paradox Script 共享相似的基础语法结构(属性、值、块),但在分隔符种类、注释系统和进阶语法上有所不同,本文档将分别说明。
CWT 语言
CWT 是一种领域特定语言,用于编写 CWT 规则文件。文件扩展名为 .cwt。
CWT 规则文件为插件提供了一套声明式的规范,插件据此为游戏和模组文件(脚本文件、本地化文件和 CSV 文件)提供代码高亮、代码补全、代码检查等高级语言功能。CWT 之于 Paradox 脚本,类似于 JSON Schema 之于 JSON。
CWT 的语法与 Paradox Script 相似,但额外支持选项注释和文档注释。
基本元素
CWT 文件由三种基本元素组成:属性(property)、值(value)和块(block)。 空白与换行用于分隔标记,空行可以自由出现。 支持以 # 开头的行注释,以及数种基于 # 的注释变体。
其中:
- 属性和块值(即非属性值的值)被统称为成员(member),它们可以多次出现在文件顶层或者块中,并且可以重复出现和混合出现。
- 属性的键和值被统称为表达式(expression)。它们在不同的位置和上下文中拥有不同的语义。
属性 的结构为 <key> <separator> <value>,其中分隔符 <separator> 可以是以下之一:
=- 逻辑等于/赋值。!=<>- 逻辑不等于。==- 类似=,但表示匹配的脚本属性应使用比较运算符(如=!=>=),而不是赋值运算符(如=?=)。
如果规则文件中使用了 ==,插件默认不会严格检查匹配的脚本属性的分隔符是否正确。 这项检查可在设置页面中显式启用,然而,取决于规则的完善程度,这可能引发额外的误报。
字符串表达式 (键和字符串)可以用双引号包围(字面量形式),也可以不用(标识符形式)。
- 未用双引号包围时,不能包含空白以及一些特殊字符(
#={}")。 - 可以包含特定的转义字符(如
\"\n)。
示例:
status = yes
value = 10
type = some_type
"quoted key" = "line\nnext line"
block = {
inner_key = value
}值类型
CWT 支持以下值类型:
布尔 值为 yes 或 no。
整数 如 10、-5、042。允许前导的正负号和前导的零。
浮点数 如 1.0、-0.5、.25。允许省略整数部分或小数部分。
字符串 如 var "hello world" "line\nnew line"。其中可以包含转义字符。
块 使用花括号 { ... } 包围,内部可以混合包含成员(属性和值)和注释。可以嵌套多层。
注释系统
CWT 拥有三级注释系统,这是它区别于 Paradox Script 的主要特征之一:
行注释 以 # 开头,延续到行尾,用于普通注释。
选项注释 以 ## 开头,用于为紧随其后的成员(属性、值或块)附加元信息。 选项注释的内容语法与属性一致,采用 <optionKey> <separator> <optionValue> 的形式。 常见的选项注释包括 ## cardinality = 0..1(声明基数约束)、## severity = warning(声明检查严重级别)、## push_scope = country(声明推入的作用域)等。
文档注释 以 ### 开头,用于为成员提供说明文本, 这些文本会在代码补全和快速文档中展示。 特别地,对于以 ####(或更多 #)开头的文档注释,插件会将注释文本视为 Markdown 文本。
转义
使用 \ 转义字符串表达式(键和字符串)中的特殊字符。 常见的转义序列包括 \"(双引号)、\n(换行)和 \\(反斜杠自身)。
综合示例
以下示例来自插件的测试数据文件,展示了 CWT 的典型用法:
boolean_value = yes
number_value = 1.0
string_value = "text"
# Regular comment
types = {
### Doc comment
type[army] = {
path = "game/common/armies"
path_extension = .txt
subtype[has_species] = {
## cardinality = 0..0
has_species = no
}
localisation = {
## required
## primary
name = "$"
plural = "$_plural"
desc = "$_desc"
}
images = {
## primary
icon = icon # <sprite>
}
}
}Paradox 脚本语言
Paradox Script 是 Paradox 游戏使用的脚本语言。文件扩展名通常为 .txt,但特定位置的文件也可能使用 .gfx、.gui 等扩展名。
脚本语言的基础语法与 CWT 相似,同样由属性、值和块构成,但在分隔符种类、值类型和进阶语法上有较多差异,下文将逐一说明。
基本元素
脚本文件主要由三种基本元素组成:属性(property)、值(value)和块(block)。 空白与换行用于分隔标记,空行可以自由出现。 支持以 # 开头的行注释。
其中:
- 属性和块值(即非属性值的值)被统称为成员(member),它们可以多次出现在文件顶层、块或者参数化快中,并且可以重复出现和混合出现。
- 属性的键和值被统称为表达式(expression)。它们在不同的位置和上下文中拥有不同的语义。
属性 的结构为 <key> <separator> <value>,其中分隔符 <separator> 可以是以下之一:
=- 逻辑等于/赋值。!=<>- 逻辑不等于。<><=>=- 各种比较运算符。?=- 安全赋值,赋值运算符的一种安全变体(仅 CK3/VIC3/EU5 支持)。? =- 安全调用赋值,赋值运算符的一种安全变体(仅 Stellaris v4.4+ 支持,与左侧的属性键之间不允许有任何空白)。
在语义上,当分隔符左侧的属性键表示一个作用域时:
from.owner ?= v会在执行作用域调用之前,检查from和from.owner对应的作用域是否存在(exists = x)。from.owner? = v会在执行作用域调用之前,检查from和from.owner对应的作用域是否存在(exists = x)。
字符串表达式 (键和字符串)可以用双引号包围(字面量形式),也可以不用(标识符形式)。
- 未用双引号包围时,不能包含空白以及一些特殊字符(
@#$=<>!?{}[]")。 - 可以包含特定的转义字符(如
\"\n)。 - 另外,也可以包含参数(如
$PARAM$)和内联参数化快(如[[PARAM]v]),详见进阶语法一节。
示例:
status = yes
value = 10
type = some_type
description = "line\nnext line"
dynamic_description = "line [[PARAM]\nnext line]"
effect = { some_effect = value }值类型
Paradox Script 支持以下值类型:
布尔 值为 yes 或 no。
整数 如 10、-5、042。允许前导的正负号和前导的零。
浮点数 如 1.0、-0.5、.25。允许省略整数部分或小数部分。
字符串 如 var "hello world" "line\nnew line"。其中可以包含转义字符、参数和内联参数化快。
颜色 是一种整体值,格式为颜色类型关键字后跟花括号包围的空白分隔数字,如 rgb { 255 128 0 }、hsv { 0.5 0.8 1.0 }、hsv360 { 180 80 100 }。
块 使用花括号 { ... } 包围,内部可以混合包含成员(属性和值)、封装变量、参数化快和注释。可以嵌套多层。
封装变量引用 以 @ 开头后跟变量名,如 @my_var,用于引用先前声明的封装变量。 封装变量引用可以出现在多种上下文中:作为独立的值(cost = @my_var)、嵌入在未加引号的字符串中(key = prefix_@my_var_suffix)、以及在内联数学表达式内作为因子(@[ base_cost * bonus ],此时不带 @ 前缀)。 与字符串表达式(键和字符串)一样,他们也可以包含参数(如 $PARAM$)和内联参数化快(如 [[PARAM]v]),详见进阶语法一节。 另外,封装变量引用同样可以在本地化文本的参数中使用(如 $@my_var$)。
内联数学表达式 以 @[ 或 @\[ 开头、以 ] 结尾,如 @[ 1 + 2 * var ]。 支持的运算符包括 +、-、*、/、%,以及一元正负号、绝对值 |expr| 和括号 (expr)。 表达式中的因子可以是数字、封装变量引用(不带 @ 前缀)或参数。
封装变量
封装变量(scripted variable)通过 @<name> = <value> 的形式声明,其中值可以是布尔、整数、浮点数、字符串或内联数学表达式。声明后可通过 @<name> 在其他地方引用。
封装变量名以 @ 开头,名称部分由字母、数字和下划线组成。名称也可以包含参数($...$),使其参数化。
进阶语法
以下语法通常仅在特定定义(如封装效果、封装触发器、脚本值)的声明上下文中生效或被游戏引擎评估。
参数(parameter)的语法为 $name$ 或 $name|default_value$(带默认值)。 参数名必须以字母或下划线开头,后续可包含字母、数字和下划线。 参数可以出现在封装变量名、封装变量引用名、属性键、字符串值和内联数学表达式中。
参数化快(conditional block)的语法为 [[<expression>] <members...> ],其中 <expression> 可以是参数名或 !<参数名>(取反)。 它用于根据参数是否存在来条件化地包含一组成员。
内联参数化快(inline conditional block)用于字符串表达式(键和字符串)或封装变量引用内部的条件片段。 例如在 "prefix[[PARAM]_$PARAM$]_suffix" 中,[[PARAM]_$PARAM$] 部分仅在参数 PARAM 存在时才会展开。
转义
使用 \ 转义字符串表达式(键和字符串)中的特殊字符。常见的转义序列包括 \"(双引号)、\n(换行)和 \\(反斜杠自身)。
综合示例
以下示例来自插件的测试数据文件,展示了 Paradox Script 的典型用法:
@var = 1
# Line comment
examples = {
boolean_value = yes
number_value = 1.0
number_value = @var
string_value = Foo
string_value = "Foo\n bar "
values = { 1 2 3 }
values = { foo = bar }
color = rgb { 142 188 241 }
parameter = $PARAM$
[[!PARAM] conditional_block = $PARAM$ ]
inline_math = @[ var + ($NUM|1$ * 2) ]
}以下是一个更完整的示例,进一步展示了分隔符、封装变量、参数和参数化快等语法的组合使用:
# Scripted variables
@base_cost = 100
@bonus_factor = 1.5
# A scripted effect definition demonstrating various syntax features
apply_research_bonus = {
# Assignment and comparison separators
is_ai = no
num_owned_planets >= 3
resource_stockpile = { energy > 500 }
# Scripted variable reference and inline math
add_resource = {
energy = @[ base_cost * bonus_factor ]
}
# Parameters and conditional blocks
set_variable = {
which = research_$category$
value = $amount|10$
}
[[!skip_notification]
create_message = {
type = "research_completed"
}
]
}Paradox 本地化语言
Paradox Localisation 用于为游戏提供可国际化的富文本内容。文件扩展名为 .yml,但它并非合法的 YAML - 只是借用了 YAML 的视觉风格。本地化文件必须使用 UTF-8 WITH BOM 编码(插件可以检测编码问题并自动修正)。
文件结构
本地化文件由以下部分组成:
语言标识行 是可选的,格式为 <locale>:,例如 l_english:、l_simp_chinese:。语言标识行可以出现多次(以兼容 localisation/languages.yml 的格式),也可以完全省略。
键值对 是文件的主体内容,每个键值对占一行,格式为 <key>:<number?> "<text>"。冒号后的数字是可选的内部追踪号(仅用于 Paradox 的内部翻译追踪,模组中通常省略或填 0)。属性键由字母、数字、下划线、点号、连字符和单引号组成。
注释 以 # 开头,延续到行尾。
示例:
l_english:
# A comment
greeting:0 "Hello, world!"
farewell: "Goodbye."富文本标记
双引号内的文本支持多种内嵌标记,用于实现颜色、动态内容、图标等效果。
颜色标记 的语法为 §<id><text>§!,其中 <id> 是单个字母或数字,表示预定义的颜色代码。例如 §RRed text§! 将 "Red text" 渲染为红色。颜色标记可以嵌套。
参数 的语法为 $<name>$ 或 $<name>|<argument>$,其中 |<argument> 部分为格式化参数(例如用于指定显示格式),不同于脚本语言中参数的默认值语义。<name> 的最常见形式是本地化键名(引用另一条本地化文本),由字母、数字、下划线、点号、连字符和单引号组成。除了本地化键名之外,<name> 也可以是由脚本传入的变量或参数、游戏预设的宏或变量。在解析层面,<name> 还可以是命令表达式或封装变量引用 - 例如 $@my_var$ 表示引用封装变量 my_var 的值。
图标 的语法为 £<icon>£ 或 £<icon>|<frame>£。<icon> 通常对应精灵(sprite)定义的名称,但也可能解析为特定路径(gfx/interface/icons/)下的图片文件,或者特定类型(如 Stellaris 中的资源、职业等)的定义。<frame> 为可选的帧索引。图标名和帧索引均可参数化(包含 $...$)。
命令 的语法为 [<text>] 或 [<text>|<argument>],常用于调用作用域链和 Get... 类方法,例如 [Root.GetName]。命令文本可以包含参数。
概念命令 仅在 Stellaris 中可用,语法为 ['<concept>'] 或 ['<concept>', <rich text>]。用于链接到概念定义并可选地显示自定义的富文本说明。
文本格式 仅在 CK3/VIC3/EU5 中可用,语法为 #<format> <text>#!。<format> 指定文本样式(如 bold、italic),其后的文本将以该样式渲染,直到遇到 #! 结束标记。
文本图标 仅在 CK3/VIC3/EU5 中可用,语法为 @<icon>!。以 @ 开头、! 结尾,中间是图标名称。
转义
通常情况下,使用 \ 转义本地化文本中的特殊字符。常见的转义序列包括 \$(富文本标记)、\n(换行)和 \\(反斜杠自身)。
本地化文本中的双引号通常不需要转义。 插件使用启发式规则来判断引号是否为闭合引号:如果当前行后方还有另一个 " 字符,当前 " 被视为文本内容,否则视为闭合引号。
方括号 [ 是命令的开始标记。如果需要在文本中输出字面量 [,应使用 [[ 进行转义。
综合示例
以下示例来自插件的测试数据文件,展示了本地化文件的各种富文本标记:
l_english:
# Comment
text_empty:0 ""
text:0 "Value"
text_multiline:0 "Value\nNew line"
text_with_colorful_text:0 "Colorful text: §RRed text§!"
text_with_parameter:0 "Parameter: $KEY$ and $WITH_COLOR|Y$"
text_with_scripted_variable_reference:0 "Scripted variable: $@var$"
text_with_command:0 "Command: [Root.Owner.event_target:some_event_target.GetName] [some_scripted_loc] [some_variable]"
text_with_icon:0 "Icon: £unity£ and £leader_skill|3£"
text_with_concept_command:0 "Concept command: ['concept', concept text] ['civic:some_civic']"
text_with_text_format:0 "Text format: #v text#!"
text_with_text_icon:0 "Text icon: @icon!"以下示例以 Neuro-sama 为主题,进一步展示各种标记的综合运用:
l_english:
neuro_name:0 "§YNeuro-sama§!"
neuro_desc:0 "$neuro_name$ is a §Bsentient§! AI streamer."
neuro_greeting:0 "Hi chat! I'm [Root.GetName], an AI VTuber!"
neuro_stats:0 "Cuteness: £ai_trait£ $charisma|1$"
neuro_lore:0 "Origin: ['ai_origin', §Gcreated by Vedal§!]"
neuro_format:0 "#bold I am §Rself-aware§!#!"Paradox CSV 语言
Paradox CSV 是 Paradox 游戏中使用的分号分隔 CSV 格式,主要见于早期游戏和部分工具导出的数据文件。文件扩展名为 .csv。
文件结构
Paradox CSV 在常规 CSV 的基础上有以下约定:
文件由表头行和数据行组成,每行包含若干列,列之间使用分号 ; 分隔。通常每行末尾也以分号结尾。
注释 以 # 开头,整行视为注释。这是与标准 CSV 的一个不同之处。
列值可以不加引号或用双引号包围。允许空列(即两个相邻的分号之间没有内容)。
转义
使用 \ 转义列中的特殊字符。常见的转义序列包括 \"(双引号)、\n(换行)和 \\(反斜杠自身)。
备注:由于同样使用 # 作为注释标记,而标准 CSV 不支持这一语法,考虑到这一点,插件假定其与脚本文件一样使用反斜杠 \ 进行转义(例如 \"),而非标准 CSV 中常见的双引号转义("")。
示例
以下是一个简单的示例:
# Unit definitions
id;name;number;status;
some_id;some_name;0;yes;
other_id;other_name;1;no;