Remove fkp (#154)

删除fkparse模块
This commit is contained in:
notify 2023-05-19 07:45:08 +08:00 committed by GitHub
parent 89dd04fd5d
commit fc3a7dbda7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 5 additions and 2887 deletions

View File

@ -70,11 +70,10 @@ jobs:
windeployqt FreeKill.exe windeployqt FreeKill.exe
cp -r ../.git . cp -r ../.git .
git restore . git restore .
rm -rf .git* android doc fkparse lib lang translations src rm -rf .git* android doc lib lang translations src
cd .. cd ..
cp lib/win/* FreeKill-release cp lib/win/* FreeKill-release
cp build/zh_CN.qm FreeKill-release cp build/zh_CN.qm FreeKill-release
cp build/fkparse/libfkparse.dll FreeKill-release
cp ../Qt/6.4.2/mingw_64/bin/li*.dll FreeKill-release cp ../Qt/6.4.2/mingw_64/bin/li*.dll FreeKill-release
cp '/c/Program Files/OpenSSL/bin/libcrypto-1_1-x64.dll' FreeKill-release cp '/c/Program Files/OpenSSL/bin/libcrypto-1_1-x64.dll' FreeKill-release
7z a -t7z FreeKill-release.7z FreeKill-release -r -mx=9 -m0=LZMA2 -ms=10m -mf=on -mhc=on -mmt=on 7z a -t7z FreeKill-release.7z FreeKill-release -r -mx=9 -m0=LZMA2 -ms=10m -mf=on -mhc=on -mmt=on
@ -86,7 +85,7 @@ jobs:
path: FreeKill-release.7z path: FreeKill-release.7z
release: release:
name: Release APK name: Release
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "fkparse"]
path = fkparse
url = https://github.com/Notify-ctrl/fkparse
[submodule "include"] [submodule "include"]
path = include path = include
url = https://github.com/Notify-ctrl/fk_headers url = https://github.com/Notify-ctrl/fk_headers

View File

@ -5,9 +5,6 @@ cmake_minimum_required(VERSION 3.16)
project(FreeKill VERSION 0.1.8) project(FreeKill VERSION 0.1.8)
add_definitions(-DFK_VERSION=\"${CMAKE_PROJECT_VERSION}\") add_definitions(-DFK_VERSION=\"${CMAKE_PROJECT_VERSION}\")
include_directories(fkparse/src)
add_subdirectory(fkparse)
find_package(Qt6 REQUIRED COMPONENTS find_package(Qt6 REQUIRED COMPONENTS
Network Network
) )

View File

@ -1,170 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
添加更多的动作语句
==================
动作语句曾经每一种作为一个单独的类出现但自从函数功能被实现后向fkparse中加入自定义action已经不是难事。下面带着例子简要介绍一下向fkparse添加动作语句的办法。
在fkparser.lua中添加接应的函数
------------------------------
下面以添加broadcastSkillInvoke为例。要调用这个函数需要room对象、技能名、音频的编号。由于fkparse中没有Room类型因为没必要让用户知道这种类型的存在因此改为需要ServerPlayer类型。
据此在fkparser.lua下面的\ ``fkp.functions``\ 表中添加以下内容:
::
broadcastSkillInvoke = function(player, skill, index)
player:getRoom():broadcastSkillInvoke(skill, index)
end,
在builtin.c中添加内置函数
-------------------------
然后进入到builtin.c的\ ``builtin_func``\ 数组下在两个NULL那一行上面插入以下内容
::
{"__broadcastSkillInvoke", "fkp.functions.broadcastSkillInvoke", TNone, 3, {
{"玩家", TPlayer, false, {.s = NULL}},
{"技能名", TString, false, {.s = NULL}},
{"音频编号", TNumber, true, {.n = -1}},
}},
这些东西是基于前面对结构体的定义而编写的。第一个字符串表示fkparse内部使用的函数名称第二个表示将要被翻译成的名称第三个表示函数的返回值类型第四个表示函数的参数数量接下来的数组表示函数的各种参数最多10个参数
参数的数组中参数的顺序必须合乎在fkparser.lua中所定义的那样各个参数的类型也一样至于参数的名称随意但是像“skill”这种需要被翻译的技能名的话参数的名称中必须包含“技能”这两个字不然的话程序会将用户输入参数的字符串原封不动复制到lua中。
关于每个参数第一个字符串是参数的名称第二个是ExpVType枚举类型表示参数的类型第三个布尔类型表示参数是不是有默认值。第四个联合体中如果没有默认值那么一律\ ``{.s = NULL}``\ 否则根据他的类型决定初始化字符串s或者整数n。这里“音频编号”的默认值是-1所以就那么填写了。
设计语法规则
------------
下面来设计新action的语法规则。
首先,语法句子中必须包含好所有非默认参数,然后语法尽可能要简明易懂,但一定不能让分析器出现移入/归约冲突之类的错误。(只要不去使用“<表达式>
的”这样的组成,这种冲突通常可以避免)。
比如将broadcastSkillInvoke的语法设计为
::
<表达式> 说出 <字符串> 的台词
这种语法看似可行包含了参数ServerPlayer和String。
补充词法单元
------------
绝大多数情况下设计的语法包含有fkparse无力处理的词语比如这里的词语“说出”和“台词”在lex.l没有定义过。
总之去lex.l中间的部分找一块地然后输入定义词法单元的内容
::
"说出" { return SPEAK; }
"台词" { return ACT_LINE; }
return后随便跟一个全大写的就行了只要不和lex.l中已经有的重复。然后前面字符串也不能是lex.l已有的也就是说不能重复定义词法规则。
然后现在return后面跟随着的全大写其实尚未定义那么去grammar.y下面将未定义词语加入
::
%token INVOKE HAVE
%token BECAUSE THROW TIMES
// 注释:前面两行是已有的,仅用来提示位置,下面一行是新加的
%token SPEAK ACT_LINE
这样就完成了词法单元的补充。
添加设计的文法
--------------
接下来就是在grammar.y中将设计好的文法加入。首先决定好文法对应非终结符号的名字自然就叫broadcastSkillInvoke了。
去grammar.y中“%%”前面一行,输入文法的定义:
::
broadcastSkillInvoke : exp SPEAK STRING FIELD ACT_LINE
;
// 注释:下面的%%和函数定义仅用来指示位置
%%
static int yyreport_syntax_error(const yypcontext_t *ctx) {
// ...
接下来是为文法加入动作语句,告诉程序该生成怎么样的\ ``func_call``\ 。参考前面已经写好的,在合适位置写下如下内容:
::
broadcastSkillInvoke : exp SPEAK STRING FIELD ACT_LINE {
tempExp = newExpression(ExpStr, 0, 0, NULL, NULL);
tempExp->strvalue = $3;
$$ = newFunccall(
strdup("__broadcastSkillInvoke"),
newParams(2, "玩家", $1, "技能名", tempExp)
);
}
;
这里稍微说明一下动作语句动作语句其实就是C语句但是加入了$$和$n这样的符号。$$表示的是当前文法左半边,$n表示的是文法右半边的第n个符号。比如这段代码中的$3就表示第三个符号即STRING$1就是第一个符号exp了。
| newFunccall的意思是创建一个新的函数调用这是fkparse用来分析的内部结构体之一。第一个参数字符串必须用strdup复制一次内存管理方便第二个参数接受一个哈希表表示这个函数调用的参数。我已经写好了一个方便的函数newParams直接构造需要的哈希表第一个参数是调用时的参数数量往后就是每一个参数名字、值、名字、值...其中值必须是ExpressionObj
\*类型,所以这边需要手动造个。
| 至此还有最后一步加入新文法的类型声明和推导规则。这里创建的是新action自然要从\ ``action_stat``\ 推导出来。
添加类型声明:
::
%type <func_call> throwCardsBySkill getUsedTimes
+ %type <func_call> broadcastSkillInvoke
%type <exp> exp prefixexp opexp
添加推导规则:
::
| throwCardsBySkill { $$ = $1; yycopyloc($$, &@$); }
| getUsedTimes { $$ = $1; yycopyloc($$, &@$); }
+ | broadcastSkillInvoke { $$ = $1; yycopyloc($$, &@$); }
;
前面带加号的行表示这是插入的新行。
编写测试例并测试
----------------
去basic.txt的某处将语句写进去
::
使用后: 你摸1张牌。
+ 你说出"生有"的台词。
+ 你说出"生有"的台词{'音频编号':1}。
重新编译出可执行文件参考README.md然后编译一下新的basic.txt打开生成的basic.lua看看效果
::
on_use = function(self, player, targets, cards)
local room = player:getRoom()
local locals = {}
global_self = self
fkp.functions.drawCards(player, 1)
fkp.functions.broadcastSkillInvoke(player, 'basic_s_6', -1)
fkp.functions.broadcastSkillInvoke(player, 'basic_s_6', 1)
end,
至此我们已经成功的新建了一个action语句剩下的就是实机测试了别忘了把改过了的fkparser.lua也复制进游戏里面。
补充文档
--------
| 新的动作语句不能没有文档,切记最后去\ ``all_action.tex``\ 中把新建的语法补充进去。
| 附注:本章中介绍的内容已经在代码中实际体现,请随意参考。

View File

@ -1,27 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
编译fkparse
===========
Linux
-----
::
$ git clone https://github.com/Notify-ctrl/fkparse
$ sudo apt install cmake flex bison
$ cd fkparse
$ mkdir build && cd build
$ cmake .. && make
Windows
-------
配置好MinGW和CMake环境从github上下载最新版的\ ``win_flex_bison``\ ,将其解压缩并设置好环境变量,然后
::
D:\> git clone https://github.com/Notify-ctrl/fkparse
D:\> cd fkparse
D:\fkparse> mkdir build && cd build
D:\fkparse\build> cmake -G "MinGW Makefiles" .. && mingw32-make

View File

@ -1,109 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
fkparse的运行原理
=================
本章大致介绍了fkparse的工作流程和源码分析。
工作流程
--------
词法和语法分析
~~~~~~~~~~~~~~
| 词法分析器和语法分析器由Flex与Bison生成。在成功打开输入文件后程序就会调用yyparse()进行语法分析具体怎么分析的我自己也不太清楚应该是按照LR分析的那种算法总之这个函数具体怎么运行的对掌握大概内容不重要分析完成并没有出现语法错误后就会往全局变量extension声明在main.h中存入一个分析完成的ExtensionObj对象。
| 关于Flex和Bison的语法这里不会十分详细的说明但会在下面稍微提一下。
分析并生成代码
~~~~~~~~~~~~~~
| 在进行完没有语法错误或者成功从语法错误中恢复了的语法分析后yyparse()将返回0然后main.c中调用函数继续分析extension并据此生成Lua代码。
| 以上就是fkparse工作的大概流程十分简单下面详细看看。
基础设施
--------
list.c
~~~~~~
基础设施之链表。里面定义了链表的创建、尾插、头插、取下标、删除某个元素、获取元素下标、获取链表长度、链表销毁等操作。
在声明其的structs.h中还含有一些常用宏如链表遍历、链表判断为空、判断是否包含某个元素等。以及从链表的函数中宏定义出来的一些栈的操作也在里面。
hash.c
~~~~~~
作为整个符号表的基础而存在的哈希表数据结构。
定义了哈希表的创建、销毁、取得数据、存放数据等等,以及许多跟哈希表内部算法有关的内容。
symtab.c
~~~~~~~~
基于哈希表而制作的跟符号表操作有关的函数。
| 为了实现全局变量和局部变量fkparse在一次分析过程中使用了许多符号表大体上每个代码块一个符号表。由于在分析代码时分析函数成为一个栈所以fkparse的符号表也是以栈的形式组织的。在一次对符号表的搜索中程序会从栈顶向栈底逐一检索当一个代码块分析完了它的符号表就从栈中弹出然后销毁掉。
| 本文件具体包括了符号表的检索、设定键值以及销毁。符号表的创建直接用创建哈希表的函数即可。
分析与中间结构
--------------
fkparse不产生语法树而是在分析过程中直接创建中间结构。
ast.c
~~~~~
曾经里面含有各种语法树的构造函数现在里面只剩个checktype了不久后将与error.c合并掉。
object.c
~~~~~~~~
含有各种中间对象的构造和析构函数以及一个很方便调用的对所有Object均适用的析构函数。
lex.c
~~~~~
Flex根据lex.l生成的词法分析器被语法分析器调用。它会读取文件中的字符串并返回合乎词法规则的token。
Flex按照贪心原则进行匹配也就是多种情况下按照最长字符串来所以它能成功区分“摸牌阶段摸牌时”和“摸”这两个词语。
grammar.c
~~~~~~~~~
Bison根据grammar.y生成的语法分析器代码。它是自底向上进行分析的在分析过程中会根据文法规则和语义动作创建相应的对象。
代码生成
--------
builtin.c
~~~~~~~~~
含有各种各样的内置函数和内置变量,以及一个初始化内置符号表的函数。
error.c
~~~~~~~
含有报错相关的各种函数。可以根据行列号将源文本输出到屏幕上考虑了汉字和其他UTF-8字符的特殊情况。
generate.c
~~~~~~~~~~
根据各种对象对症下药生成对应的Lua代码。
main.c
~~~~~~
主函数说实话不是那么重要fkparse到后期估计会以dll/so这样库的形式登场吧。
其他
----
fkparser.lua
~~~~~~~~~~~~
生成的Lua运行起来所必备的种种函数毕竟直接生成神杀的Lua难度很高。
test/\*.txt
~~~~~~~~~~~
fkparse开发时的测试用例。

View File

@ -1,11 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
FKP开发者指南
=============
.. toctree::
:maxdepth: 1
build_from_source.rst
how_does_it_work.rst
add_more_action.rst

View File

@ -1,653 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
所有的动作语句
==============
先列出语句格式,再依次说明表达式类型需求,最后说返回值(如果有)。
前面有个没说过的动作语句也可以带额外参数毕竟一句话没法描述完全部的情况。因此对于一部分动作语句也提供了一些额外的参数像函数那样用就行了具体参考已有的txt。
摸牌
----
::
<表达式> 摸 <表达式> 张牌
玩家类型;数字类型
失去体力
--------
::
<表达式> 失去 <表达式> 点体力
玩家类型;数字类型
失去体力上限
------------
::
<表达式> 失去 <表达式> 点体力上限
玩家类型;数字类型
造成伤害
--------
::
<表达式> 对 <表达式> 造成 <表达式> 点伤害
| 玩家类型;玩家类型;数字类型
| 额外参数:
- ``'伤害属性'``\ :数字类型,默认为\ ``'无属性'``
- ``'造成伤害的牌'``\ :卡牌类型,默认为\ ``nil``
- ``'造成伤害的原因'``\ :字符串类型,默认为空字符串
受到伤害
--------
::
<表达式> 受到 <表达式> 点伤害
| 玩家类型;数字类型
| 额外参数同上。
回复体力
--------
::
<表达式> 回复 <表达式> 点体力
| 玩家类型;数字类型
| 额外参数:
- ``'回复来源'``\ :玩家类型,默认为\ ``nil``
- ``'回复的牌'``\ :卡牌类型,默认为\ ``nil``
回复体力上限
------------
::
<表达式> 回复 <表达式> 点体力上限
玩家类型;数字类型
获得技能
--------
::
<表达式> 获得技能 <表达式>
玩家类型;字符串类型
失去技能
--------
::
<表达式> 失去技能 <表达式>
玩家类型;字符串类型
获得标记
--------
::
<表达式> 获得 <表达式> 枚 <字符串> [隐藏] 标记
玩家类型;数字类型
<字符串>表示标记的名称。
注:“隐藏”可填可不填,如果写了是隐藏标记的话,获得标记将不会显示在战报中,也没有图片,可以借此实现技能发动次数控制等。
失去标记
--------
::
<表达式> 失去 <表达式> 枚 <字符串> [隐藏] 标记
玩家类型;数字类型
统计标记数量
------------
::
<表达式> <字符串> [隐藏] 标记数量
玩家类型
返回:数字类型
询问选择选项
------------
::
<表达式> 从 <表达式> 选择一项
| 玩家类型;数组(字符串类型)
| 额外参数:
- ``'选择的原因'``\ :字符串类型,默认为空字符串
返回:字符串类型
询问选择玩家
------------
::
<表达式> 从 <表达式> 选择一名角色
| 玩家类型;数组(玩家类型)
| 额外参数:
- ``'选择的原因'``\ :字符串类型,默认为空字符串
- ``'提示框文本'``\ :字符串类型,默认为默认的提示文本
- ``'可以点取消'``\ :布尔类型,默认为\ ````
- ``'提示技能发动'``\ :布尔类型,默认为\ ````
返回:玩家类型
询问发动技能
------------
::
<表达式> 选择发动 <字符串>
玩家类型
<字符串>是技能的中文名字,且只能是本文件中已经定义的技能。定义的先后顺序不重要
返回:布尔类型
获得卡牌
--------
::
<表达式> 获得卡牌 <表达式>
| 玩家类型;卡牌类型
| 额外参数:
- ``'公开'``\ :布尔类型,默认为\ ````
拥有技能
--------
::
<表达式> 拥有技能 <字符串>
玩家类型
<字符串>是技能的中文名字,且只能是本文件中已经定义的技能。定义的先后顺序不重要
返回:布尔类型
因发动技能而弃牌
----------------
::
<表达式> 因技能 <字符串> 弃置卡牌 <表达式>
玩家类型;卡牌数组
<字符串>是技能的中文名字,且只能是本文件中已经定义的技能。定义的先后顺序不重要
本语句只能用在主动技的效果中。
主动技的发动次数
----------------
::
<表达式> 发动主动技 <字符串> 的次数
玩家类型;卡牌数组
<字符串>是技能的中文名字,且只能是本文件中已经定义的技能。定义的先后顺序不重要
这种办法只能获取当前阶段里面发动那个技能的次数。如果想要做一回合发动多少次的技能,请使用隐藏标记实现。
令角色弃牌
----------
::
<表达式> 弃置 <表达式> 张牌
| 玩家类型;数字类型
| 额外参数:
- ``'技能名'``: 发起这次弃牌的技能名,默认为空字符串。
- ``'最小弃置数量'``: 数字类型,默认为要求弃牌数量的值。
- ``'可以点取消'``:
布尔类型,是否可以点击取消拒绝弃牌,默认为\ ````\ 。
- ``'可以弃装备'``: 布尔类型,是否可以弃置装备牌,默认为\ ````\ 。
- ``'提示信息'``: 字符串类型,默认为空字符串(默认的提示信息)。
- ``'弃牌规则'``: 字符串类型,默认为无限制。
返回类型:卡牌数组,即目标角色弃置了的牌,可能是空的数组。
播放台词
--------
::
<表达式> 说出 <字符串> 的台词
如果有多个编号完的音频还需要选择,在后面加上{’音频编号’: <编号>}。
交换座位
--------
::
<表达式> 与 <表达式> 交换座位
表达式均为玩家类型。
没有其他参数。
洗牌
----
::
<表达式> 洗牌
表达式均为玩家类型。
没有其他参数。
变身
----
::
<表达式> 变身为 <字符串>
表达式为玩家类型,字符串为要变身的武将,应使用内部标识。
其他参数:
- ``'是否满状态'`` 布尔类型,默认为\ ````
- ``'是否以开始游戏状态变身'`` 布尔类型,默认为\ ````
- ``'是否是变更副将'``
布尔类型,默认为\ ````\ (即变更主将,而且一般也只能变更主将)
- ``'是否发送信息'`` 布尔类型,默认为\ ````
判定
----
::
<表达式> 判定
| 玩家类型
| 额外参数:
- ``'技能名'``: 发起这次判定的技能名,默认为空字符串。
- ``'最小弃置数量'``: 数字类型,默认为要求弃牌数量的值。
- ``'判定规则'``:
字符串类型,表示判定牌需要的某种规则,默认为任意卡牌。
- ``'希望判定中'``:
布尔类型,是否希望获得\ ``'判定规则'``\ 中描述的判定结果,默认为\ ````\ 。
- ``'提示信息'``: 布尔类型,是否会播放打钩打叉动画,默认为\ ````\ 。
类观星技能
----------
适用于“将一些牌以任意顺序放在牌堆顶/牌堆底/两者都有”的场合。
::
<表达式> 对 <表达式> 进行观星
第一个表达式为执行观星的玩家,第二个表达式为此技能处理的牌列表。
额外参数:
- ``'观星类型'``:
指定卡组能够放置的位置,共三种选择:\ ``'顶部底部均放置'``\ 、\ ``'只放置顶部'``\ 、\ ``'只放置底部'``\ 。默认为\ ``'顶部底部均放置'``\ 。
选取牌堆顶X张牌
---------------
::
<表达式> 选择牌堆顶 <表达式> 张牌
第一个表达式为执行行动的玩家,第二个表达式为牌的数量。
额外参数:
- ``'是否不放回'``:
布尔类型,被选取的卡牌是否在处理结束后直接置入弃牌堆。默认为\ ``'真'``\ 。
改判
----
::
<表达式> 将判定结果修改为 <表达式>
第一个是玩家,第二个是要修改的牌。
额外参数:
- ``'技能名'``:
字符串类型,处理区改判牌显示的技能名。默认没有,但是建议写成技能的名字。
- ``'是否交换'``:
布尔类型,是否将原来的判定牌与改判的牌置换。默认为\ ``'假'``\ 。
特别注意:调用此语句需将时机设定为“改判前”。
要求选择自己一张牌
------------------
::
<表达式> 选择自己的一张牌
玩家类型
令玩家选择自己的任意一张牌。
额外参数:
- ``'选牌规则'`` 字符串类型,表示选牌的具体规则,默认为任意卡牌。
- ``'提示'`` 字符串类型,为选牌的提示信息,默认为默认的提示。
- ``'技能名'`` 字符串类型,默认为当前的技能。
要求使用一张牌
--------------
::
<表达式> 使用一张牌
玩家类型。
额外参数:
- ``'选牌规则'`` 字符串类型,表示选牌的具体规则,默认为任意卡牌。
- ``'提示'`` 字符串类型,为选牌的提示信息,默认为空。
- ``'目标'`` 玩家类型,本次要求使用卡牌需指定的目标。
- ``'技能名'`` 字符串类型,默认为空。
要求打出一张牌
--------------
::
<表达式> 打出一张牌
玩家类型。
额外参数:
- ``'选牌规则'`` 字符串类型,表示选牌的具体规则,默认为任意卡牌。
- ``'提示'`` 字符串类型,为选牌的提示信息,默认为空。
- ``'是否为改判'`` 布尔类型,默认为假。
- ``'技能名'`` 字符串类型,默认为空。
选择他人一张牌
--------------
::
<表达式> 选择 <表达式> 一张牌
两个参数均为玩家类型
用来令玩家1选择玩家2的一张牌像过河拆桥的弹窗那样。
额外参数:
- ``'位置'`` 数字数组,表示可以被选牌的区域,默认为只有手牌区。
- ``'原因'`` 字符串类型,表示被选牌的原因,默认为空。
- ``'是否可见手牌'`` 布尔类型,默认为假。
聊天
----
::
<表达式> 说出 <表达式>
玩家类型;字符串类型/数字类型
本语句可以让一名玩家在聊天框中发送一句话。
发送战报
--------
::
<表达式> 发送战报 <表达式>
| 玩家类型;字符串类型
| 额外参数:
- ``'%from'``:
玩家类型。将以玩家使用的武将名替换战报文本的所有“%from”。
- ``'%to'``: 玩家类型。将以玩家使用的武将名替换战报文本的所有“%to”。
- ``'%card'``:
卡牌类型。将以形如“杀[♣7]”的形式替换战报文本中的所有“%card”。
- ``'%arg'``: 任意类型。将替换战报文本中的所有“%arg”。
- ``'%arg2'``: 任意类型。将替换战报文本中的所有“%arg2”。
弃置牌
------
::
<表达式> 弃置牌 <表达式>
玩家类型;卡牌数组类型
| 本语句可以直接弃置某一名玩家的相应卡牌。
| 额外参数:
- ``'来源'``:
玩家类型本次弃牌的来源。比如A拆掉B的一张牌那么语句是B弃置牌xxx而来源是A。
- ``'技能名'``: 字符串类型,与本次弃牌相关的技能。默认为当前的技能。
换牌
----
::
<表达式> 与 <表达式> 换牌
| 玩家类型;玩家类型
| 额外参数:
- ``'区域'``: 要换牌的区域,可以为手牌区或装备区,默认为手牌区。
- ``'技能名'``: 字符串类型,与本次弃牌相关的技能。默认为当前的技能。
给牌
----
::
<表达式> 交给 <表达式> 牌 <表达式>
| 玩家类型;玩家类型;卡牌数组类型
| 额外参数:
- ``'公开'``: 布尔类型,本次给牌是否正面朝上。默认为不公开。
- ``'技能名'``: 字符串类型,与本次弃牌相关的技能。默认为当前的技能。
拼点
----
::
<表达式> 与 <表达式> 拼点
| 玩家类型;玩家类型
| 额外参数:
- ``'技能名'``: 字符串类型,与本次弃牌相关的技能。默认为当前的技能。
返回:拼点信息
参见“类型可以获取的属性”一章以详细了解如何处理拼点的结果。
翻面
----
::
<表达式> 翻面
玩家类型
进行额外回合
------------
::
<表达式> 进行额外回合
玩家类型
跳过阶段
--------
::
<表达式> 跳过 <表达式>
玩家类型;要跳过的阶段
注意:跳过阶段的语句只能用在自己回合内,且需要跳过的阶段还没有开始的情况下。我个人建议在上个阶段即将结束时去跳过想要跳过的阶段,不然战报会显得很奇怪。
检测在攻击范围内
----------------
::
<表达式> 在 <表达式> 攻击范围内
两个参数均为玩家类型,返回布尔类型:前者是否在后者攻击范围内。
额外参数:
- ``'距离修正'``\ 数字类型对距离结果的修正值默认为0。
两人距离
--------
::
<表达式> 到 <表达式> 距离
两个参数均为玩家类型,返回数字类型:前者到后者的距离。
额外参数:
- ``'距离修正'``\ 数字类型对距离结果的修正值默认为0。
检测座次是否相邻
----------------
::
<表达式> 与 <表达式> 相邻
两个参数均为玩家类型,返回布尔类型:前者是否与后者相邻。
获取其他角色
------------
::
<表达式> 之外的其他角色
玩家类型
获取所给的玩家的所有其他角色
获取技能的发动次数
------------------
::
<表达式> 本轮发动过 <表达式> 的次数
<表达式> 本回合发动过 <表达式> 的次数
<表达式> 本阶段发动过 <表达式> 的次数
玩家类型;字符串类型
获取某玩家在某个时间段内发动过某个技能的次数
只能获取使用fkparse自定义技能的发动次数其他的无法。同时也不提供对多个效果各自发动次数的支持。
设定【杀】需要的【闪】数
------------------------
::
<表达式>令对<表达式>使用的杀需<表达式>张闪响应
玩家类型,玩家类型,数字类型。
特别的“需0张闪响应”=此【杀】不可被【闪】响应。
注意:此语句只能在“确定目标后”这一时机使用。

View File

@ -1,192 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
所有触发时机
============
下表列出了所有触发时机,以及它们对应的相关变量。
(摸鱼了,没写完所有变量)
.. container:: center
+---------------------------+---------------------------+------------+
| **时机** | **相关变量** | **可重写** |
+===========================+===========================+============+
| 游戏开始时 | | |
+---------------------------+---------------------------+------------+
| 回合即将开始时 | | |
+---------------------------+---------------------------+------------+
| 阶段开始时 | | |
+---------------------------+---------------------------+------------+
| 阶段结束时 | | |
+---------------------------+---------------------------+------------+
| 阶段被跳过时 | | |
+---------------------------+---------------------------+------------+
| 摸牌阶段摸牌时 | ` | |
| | `'摸牌数量'``\ :数字类型 | |
+---------------------------+---------------------------+------------+
| 摸牌阶段摸牌后 | 同上 | |
+---------------------------+---------------------------+------------+
| 分发起始手牌时 | 同上 | |
+---------------------------+---------------------------+------------+
| 分发起始手牌后 | 同上 | |
+---------------------------+---------------------------+------------+
| 回复体力时 | | |
+---------------------------+---------------------------+------------+
| ` | | |
| `'回复的牌'``\ :卡牌类型 | | |
+---------------------------+---------------------------+------------+
| ``'回复值'``\ :数字类型 | | |
+---------------------------+---------------------------+------------+
| 回复体力后 | 同上 | |
+---------------------------+---------------------------+------------+
| 失去体力前 | ``'失去值'``\ :数字类型 | |
+---------------------------+---------------------------+------------+
| 失去体力后 | 同上 | |
+---------------------------+---------------------------+------------+
| 体力变化后 | | |
+---------------------------+---------------------------+------------+
| 体力上限变化后 | | |
+---------------------------+---------------------------+------------+
| 失去技能后 | ``'技能'``\ :字符串类型 | |
+---------------------------+---------------------------+------------+
| 获得技能后 | 同上 | |
+---------------------------+---------------------------+------------+
| 开始判定时 | | |
+---------------------------+---------------------------+------------+
| 改判前 | | |
+---------------------------+---------------------------+------------+
| 改判后 | | |
+---------------------------+---------------------------+------------+
| 判定完成后 | | |
+---------------------------+---------------------------+------------+
| 拼点时 | | |
+---------------------------+---------------------------+------------+
| 拼点后 | | |
+---------------------------+---------------------------+------------+
| 翻面后 | | |
+---------------------------+---------------------------+------------+
| 连环状态改变后 | | |
+---------------------------+---------------------------+------------+
| 造成伤害时 | | |
+---------------------------+---------------------------+------------+
| ` | | |
| `'伤害目标'``\ :玩家类型 | | |
+---------------------------+---------------------------+------------+
| ``'造 | | |
| 成伤害的牌'``\ :卡牌类型 | | |
+---------------------------+---------------------------+------------+
| ``'伤害值'``\ :数字类型 | | |
+---------------------------+---------------------------+------------+
| ``'伤害属性 | | |
| '``\ :枚举值(数字类型) | | |
+---------------------------+---------------------------+------------+
| ``'造成伤 | | |
| 害的原因'``\ :字符串类型 | | |
+---------------------------+---------------------------+------------+
| ``' | | |
| 伤害被防止'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| ``'伤害 | | |
| 是传导伤害'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| 受到伤害时 | 同上 | |
+---------------------------+---------------------------+------------+
| 造成伤害后 | 同上 | |
+---------------------------+---------------------------+------------+
| 受到伤害后 | 同上 | |
+---------------------------+---------------------------+------------+
| 造成伤害结算完成后 | 同上 | |
+---------------------------+---------------------------+------------+
| 进入濒死时 | | |
+---------------------------+---------------------------+------------+
| ``'濒死 | | |
| 的伤害来源'``\ :玩家类型 | | |
+---------------------------+---------------------------+------------+
| ``'造成濒死 | | |
| 的伤害的牌'``\ :卡牌类型 | | |
+---------------------------+---------------------------+------------+
| ``'濒 | | |
| 死的伤害值'``\ :数字类型 | | |
+---------------------------+---------------------------+------------+
| ``'濒死的伤害属性 | | |
| '``\ :枚举值(数字类型) | | |
+---------------------------+---------------------------+------------+
| ``'造成濒死的伤 | | |
| 害的原因'``\ :字符串类型 | | |
+---------------------------+---------------------------+------------+
| ``'濒死的 | | |
| 伤害被防止'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| ``'濒死的伤害 | | |
| 是传导伤害'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| 进入濒死后 | 同上 | |
+---------------------------+---------------------------+------------+
| 脱离濒死后 | 同上 | |
+---------------------------+---------------------------+------------+
| 求桃开始时 | 同上 | |
+---------------------------+---------------------------+------------+
| 求桃完成后 | 同上 | |
+---------------------------+---------------------------+------------+
| 角色阵亡时 | | |
+---------------------------+---------------------------+------------+
| ``'死亡 | | |
| 的伤害来源'``\ :玩家类型 | | |
+---------------------------+---------------------------+------------+
| ``'造成死亡 | | |
| 的伤害的牌'``\ :卡牌类型 | | |
+---------------------------+---------------------------+------------+
| ``'死 | | |
| 亡的伤害值'``\ :数字类型 | | |
+---------------------------+---------------------------+------------+
| ``'死亡的伤害属性 | | |
| '``\ :枚举值(数字类型) | | |
+---------------------------+---------------------------+------------+
| ``'造成死亡的伤 | | |
| 害的原因'``\ :字符串类型 | | |
+---------------------------+---------------------------+------------+
| ``'死亡的 | | |
| 伤害被防止'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| ``'死亡的伤害 | | |
| 是传导伤害'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| 阵亡后判定胜负前 | 同上 | |
+---------------------------+---------------------------+------------+
| 阵亡后判定胜负时 | 同上 | |
+---------------------------+---------------------------+------------+
| 打出卡牌时 | | |
+---------------------------+---------------------------+------------+
| ``' | | |
| 响应的目标'``\ :玩家类型 | | |
+---------------------------+---------------------------+------------+
| ``'响应 | | |
| 的牌被使用'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| ``'响应 | | |
| 的牌被改判'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| ``'响应 | | |
| 的牌是手牌'``\ :布尔类型 | | |
+---------------------------+---------------------------+------------+
| 打出卡牌后 | 同上 | |
+---------------------------+---------------------------+------------+
| 卡牌移动前 | | |
+---------------------------+---------------------------+------------+
| 卡牌移动后 | | |
+---------------------------+---------------------------+------------+
| 卡牌使用后 | | |
+---------------------------+---------------------------+------------+
| 指定目标时 | | |
+---------------------------+---------------------------+------------+
| 确定目标时 | | |
+---------------------------+---------------------------+------------+
| 指定目标后 | | |
+---------------------------+---------------------------+------------+
| 确定目标后 | | |
+---------------------------+---------------------------+------------+
| 卡牌生效后 | | |
+---------------------------+---------------------------+------------+
| 卡牌结算完成后 | | |
+---------------------------+---------------------------+------------+

View File

@ -1,128 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
所有的预定义函数
================
fkparse提供了一些内置函数供您使用。
随机数
------
函数名称:\ ``'生成随机数'``
功能:生成一个范围为[下界,上界]的随机数。
参数:
- ``'上界'``\ 数字类型默认为10
- ``'下界'``\ 数字类型默认为1
返回:数字类型
提示信息
--------
函数名称:\ ``'创建提示信息'``
功能:根据给定的各种参数,构造一个提示信息。
参数:
- ``'文本'``\ :字符串类型,无默认值
- ``'玩家1'``\ :玩家类型,默认为空
- ``'玩家2'``\ :玩家类型,默认为空
- ``'变量1'``\ :数字类型或者字符串类型,默认为空
- ``'变量2'``\ :数字类型或者字符串类型,默认为空
返回:字符串类型
| 说明:
| 在这个函数中,提示信息的主体由\ ``'文本'``\ 决定。在\ ``'文本'``\ 中,可以通过如下方式向文本中引入变量:
- ``%src``: 对应着参数\ ``'玩家1'``\ ,它会被替换为对应玩家的武将名称
- ``%dest``: 对应着参数\ ``'玩家2'``\ ,它会被替换为对应玩家的武将名称
- ``%arg``: 对应着参数\ ``'变量1'``\ ,被替换为对应的值
- ``%arg2``: 对应着参数\ ``'变量2'``\ ,被替换为对应的值
卡牌规则
--------
函数名称:\ ``'创建卡牌规则'``
功能:根据给定的各种参数,构造一个能判定卡牌是否符合类型的字符串。
参数:
- ``'牌名表'``\ :保存着所有可行牌名的列表,默认为所有牌名
- ``'花色表'``\ :保存着所有可行花色的列表,默认为所有牌名
- ``'点数表'``\ :保存着所有可行点数的列表,默认为所有牌名
返回:字符串类型
虚拟牌
------
函数名称:\ ``'创建虚拟牌'``
功能:根据给定的各种参数,构造一张虚拟牌。注意这边“虚拟牌”和规则集说的“虚拟牌”不是一个东西。
参数:
- ``'点数'``\ :数字类型,保存着虚拟牌的点数,默认由游戏自行判断,一般可不填
- ``'花色'``\ :字符串类型,虚拟牌的花色,默认由游戏自行判断,一般可不填
- ``'牌名'``\ :字符串类型,即虚拟牌的牌名,默认为普通杀
- ``'子卡牌'``\ :卡牌数组类型,保存着虚拟牌的子卡牌(即其对应的实体卡),默认为空
- ``'技能名'``\ :字符串类型,表示创建该虚拟牌的技能名,默认为当前技能的名字
| 说明:
| 太阳神三国杀“自行判断”花色和点数的行为可能与规则集有所出入,特于此说明。
- 虚拟牌的颜色取决于所有子卡牌的颜色,只要子卡牌的颜色都相同,那么虚拟牌也是那个颜色。否则虚拟牌的颜色为无色。除非子卡牌刚好只有一张,虚拟牌都是没有花色的。
- 虚拟牌的点数为所有子卡牌点数之和最大为K若没有子卡牌则没有点数。
返回:卡牌类型
移动卡牌
--------
函数名称:\ ``'创建卡牌移动信息'``
功能:根据给定的参数,构造一个卡牌移动信息
参数:
- ``'卡牌列表'``\ :卡牌数组类型,本次要被移动的所有卡牌。无默认值
- ``'移动目标区域'``\ :卡牌将要被移动到的区域。无默认值
- ``'移动目标角色'``\ :卡牌将要被移动到的玩家。默认为不存在,但如果确实有目标玩家的话必须手动指定
- ``'移牌原因'``\ :移牌的原因,默认为“获得牌”
- ``'技能名'``\ :字符串类型,表示移动本牌的技能名,默认为当前技能的名字
- ``'公开'``\ :布尔类型,本次移动卡牌是否对所有人公开(正面朝上)。默认为公开
| 返回:移牌信息
| 函数名称:\ ``'移动卡牌'``
功能:同时对参数表中给出的所有移牌信息执行实际的移动。
参数:
- ``'移牌信息列表'``\ :移牌信息的数组,里面是需要同时移动的所有移动信息。无默认值

View File

@ -1,62 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
所有词法单元
============
emmm...想不出什么更好的词了。这里所谓的词法单元就是像\ ``<势力>、<性别>``\ 之类的有固定取值范围,并且不需要打单双引号的东西。
势力
----
- 魏
- 蜀
- 吴
- 群
- 神
性别
----
- 男性
- 女性
- 中性
技能频率
--------
- 锁定技
- 普通技
- 默认技
- 觉醒技
- 限定技
类型标识符
----------
- 数字类型
- 布尔类型
- 字符串类型
- 玩家类型
- 卡牌类型
- 数字数组
- 字符串数组
- 玩家数组
- 卡牌数组

View File

@ -1,75 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
类型可以获取的属性
==================
玩家类型
--------
- ``"体力值"``
- ``"手牌数"``
- ``"体力上限"``
- ``"当前阶段"``
- ``"身份"``
- ``"性别"``
- ``"手牌上限"``
- ``"座位号"``
- ``"势力"``
- ``"存活状态"``
- ``"死亡状态"``
- ``"攻击距离"``
卡牌类型
--------
- ``"点数"``
- ``"花色"``
- ``"类别"``
- ``"牌名"``
- ``"编号"``
- ``"是否被装备"``
- ``"所在位置"``
- ``"持有者"``
数组
----
- ``"长度"``
拼点结果
--------
- ``"来源"``: 玩家类型,拼点发起者
- ``"目标"``: 玩家类型,拼点接受者
- ``"来源卡牌"``: 卡牌类型,发起者的拼点牌
- ``"目标卡牌"``: 卡牌类型,对方的拼点牌
- ``"来源点数"``:
数字类型,发起者的拼点点数(有些技能会影响拼点点数,故需要单独安排一个属性)
- ``"目标点数"``: 数字类型,对方的拼点点数。
- ``"原因"``: 字符串类型,拼点的原因。一般是技能名字。
- ``"获胜者"``: 玩家类型,拼点获胜者。有可能不存在,请特别注意。

View File

@ -1,224 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
所有的预定义变量
================
下表是所有预定义好了的变量。它们都不能被赋值语句赋值。
表中的数字类型可能指的是枚举值。请自行判断。
为了方便而用的变量
------------------
.. container:: center
============== ================
**变量名** **类型**
============== ================
```` 玩家类型
``不存在的`` 任意类型
``'所有角色'`` 数组(玩家类型)
============== ================
势力
----
.. container:: center
========== ========
**变量名** **类型**
========== ========
``'魏'`` 数字类型
``'蜀'`` 数字类型
``'吴'`` 数字类型
``'群'`` 数字类型
``'神'`` 数字类型
========== ========
花色
----
.. container:: center
============ ==========
**变量名** **类型**
============ ==========
``'黑桃'`` 字符串类型
``'红桃'`` 字符串类型
``'梅花'`` 字符串类型
``'方块'`` 字符串类型
``'无花色'`` 字符串类型
============ ==========
卡牌类型
--------
.. container:: center
============ ========
**变量名** **类型**
============ ========
``'基本牌'`` 数字类型
``'装备牌'`` 数字类型
``'锦囊牌'`` 数字类型
============ ========
卡牌区域
--------
.. container:: center
============== ========
**变量名** **类型**
============== ========
``'手牌区'`` 数字类型
``'装备区'`` 数字类型
``'判定区'`` 数字类型
``'武将牌上'`` 数字类型
``'弃牌堆'`` 数字类型
``'牌堆'`` 数字类型
``'处理区'`` 数字类型
============== ========
伤害属性
--------
.. container:: center
============ ========
**变量名** **类型**
============ ========
``'无属性'`` 数字类型
``'火属性'`` 数字类型
``'雷属性'`` 数字类型
============ ========
玩家的当前阶段
--------------
.. container:: center
============== ========
**变量名** **类型**
============== ========
``'开始阶段'`` 数字类型
``'准备阶段'`` 数字类型
``'判定阶段'`` 数字类型
``'摸牌阶段'`` 数字类型
``'出牌阶段'`` 数字类型
``'弃牌阶段'`` 数字类型
``'结束阶段'`` 数字类型
``'回合外'`` 数字类型
============== ========
身份
----
.. container:: center
========== ========
**变量名** **类型**
========== ========
``'主公'`` 数字类型
``'忠臣'`` 数字类型
``'反贼'`` 数字类型
``'内奸'`` 数字类型
========== ========
预定义牌名
----------
.. container:: center
================ ==========
**变量名** **类型**
================ ==========
``'杀'`` 字符串类型
``'闪'`` 字符串类型
``'桃'`` 字符串类型
``'酒'`` 字符串类型
``'过河拆桥'`` 字符串类型
``'顺手牵羊'`` 字符串类型
``'决斗'`` 字符串类型
``'借刀杀人'`` 字符串类型
``'无中生有'`` 字符串类型
``'无懈可击'`` 字符串类型
``'南蛮入侵'`` 字符串类型
``'万箭齐发'`` 字符串类型
``'桃园结义'`` 字符串类型
``'五谷丰登'`` 字符串类型
``'闪电'`` 字符串类型
``'乐不思蜀'`` 字符串类型
``'诸葛连弩'`` 字符串类型
``'青釭剑'`` 字符串类型
``'寒冰剑'`` 字符串类型
``'雌雄双股剑'`` 字符串类型
``'青龙偃月刀'`` 字符串类型
``'丈八蛇矛'`` 字符串类型
``'贯石斧'`` 字符串类型
``'方天画戟'`` 字符串类型
``'麒麟弓'`` 字符串类型
``'八卦阵'`` 字符串类型
``'仁王盾'`` 字符串类型
``'的卢'`` 字符串类型
``'绝影'`` 字符串类型
``'爪黄飞电'`` 字符串类型
``'赤兔'`` 字符串类型
``'大宛'`` 字符串类型
``'紫骍'`` 字符串类型
``'雷杀'`` 字符串类型
``'火杀'`` 字符串类型
``'古锭刀'`` 字符串类型
``'藤甲'`` 字符串类型
``'兵粮寸断'`` 字符串类型
``'铁索连环'`` 字符串类型
``'白银狮子'`` 字符串类型
``'火攻'`` 字符串类型
``'朱雀羽扇'`` 字符串类型
``'骅骝'`` 字符串类型
================ ==========
性别
----
.. container:: center
========== ========
**变量名** **类型**
========== ========
``'男性'`` 数字类型
``'女性'`` 数字类型
``'中性'`` 数字类型
========== ========
观星用
------
.. container:: center
==================== ========
**变量名** **类型**
==================== ========
``'只放置顶部'`` 数字类型
``'顶部底部均放置'`` 数字类型
``'只放置底部'`` 数字类型
==================== ========
移牌原因
--------
.. container:: center
================== ========
**变量名** **类型**
================== ========
``'因使用而移动'`` 数字类型
``'因打出而移动'`` 数字类型
``'因弃置而移动'`` 数字类型
``'因重铸而移动'`` 数字类型
``'因拼点而移动'`` 数字类型
``'因摸牌而移动'`` 数字类型
``'因置入而移动'`` 数字类型
``'因交给而移动'`` 数字类型
``'因换牌而移动'`` 数字类型
================== ========

View File

@ -1,86 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
关键词中英文对照
================
为了编码方便编程的基本都懒得切换输入法fkparse对一些常用关键词提供了英文、其他编程语言中的等价输入形式。
(多个等价形式用逗号分开)
.. container:: center
===================== ====================
**关键词** **等价形式**
===================== ====================
``拓展包`` ``Package``
``触发技`` ``TriggerSkill``
``时机:`` ``Event:``
``条件:`` ``Condition:``
``效果:`` ``Effect:``
```` ``let``
```` ``=,equal``
```` ``if``
```` ``then``
``否则若`` ``elseif``
``否则`` ``else``
``以上`` ``end``
``重复此流程:`` ``repeat``
``直到`` ``until``
```` ``.``
``返回`` ``return``
```` ``false``
```` ``true``
``中止此流程`` ``break``
``定义函数`` ``def``
``调用`` ``call``
``主动技`` ``ActiveSkill``
``选牌规则:`` ``CardFilter:``
``选目标规则:`` ``TargetFilter:``
``可以点确定:`` ``Feasible:``
``使用后:`` ``AfterUse:``
``视为技`` ``ViewAsSkill``
``视为规则:`` ``ViewAsRule:``
``响应条件:`` ``Responsable:``
``响应规则:`` ``ResponseRule:``
``状态技`` ``StatusSkill``
``禁止指定目标:`` ``Prohibited:``
``距离修正:`` ``DistanceCorrect:``
``手牌上限修正:`` ``Maxcards Extra:``
``手牌上限固定:`` ``Maxcards Fixed:``
``出牌次数修正:`` ``Residue:``
``出牌距离修正:`` ``DistanceLimit:``
``出牌目标数量修正:`` ``ExtraTarget:``
``攻击范围修正:`` ``AtkRange Extra:``
``攻击范围固定:`` ``AtkRange Fixed:``
``锁定技`` ``Compulsory``
``普通技`` ``NotFrequent``
``默认技`` ``Frequent``
``觉醒技`` ``Wake``
``限定技`` ``Limited``
``男性`` ``Male``
``女性`` ``Female``
``中性`` ``Neuter``
```` ``Wei``
```` ``Shu``
```` ``Wu``
```` ``Qun``
```` ``God``
``数字类型`` ``TNumber``
``布尔类型`` ``TBool``
``字符串类型`` ``TString``
``玩家类型`` ``TPlayer``
``卡牌类型`` ``TCard``
``数字数组`` ``TNumberList``
``字符串数组`` ``TStringList``
``玩家数组`` ``TPlayerList``
``卡牌数组`` ``TCardList``
``无类型`` ``TNone``
``大于`` ``>``
``小于`` ``<``
``不是`` ``~=,!=``
```` ``==``
``不小于`` ``>=``
``不大于`` ``<=``
```` ``and,&&``
```` or,|\|
===================== ====================

View File

@ -1,15 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
FKP参考手册
===========
.. toctree::
:maxdepth: 1
all_lexical.rst
all_event.rst
all_var.rst
all_function.rst
all_action.rst
all_property.rst
cn_en.rst

View File

@ -1,100 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
主动技能
========
主动技能概述
------------
所谓主动技能,就是那些可以在出牌阶段时主动发动的技能,例如制衡、仁德、强袭等等。在三国杀移动版中,主动技能通常在技能列表中显示为一个可以按下的按钮。
在fkparse中创建主动技能的语法格式为
::
主动技 条件:<代码块> 选牌规则:<代码块> 选目标规则:<代码块>
可以点确定:<代码块> 使用后:<代码块>
这里需要注意的是,上面所描述的格式,隶属于前面所说过的\ ``<技能主体内容>``\ 中,也就是说要创建主动技能的话,仍然需要补充前面的“导语部分”。
下面来一一叙述各个\ ``代码块``\ 的意义。
条件
~~~~
条件指的是主动技能不能被使用。更加确切的说,“条件”是指技能按钮需要被点亮的一系列条件,如果这些条件不能满足的话,技能按钮就会显示为灰色。例如技能“制衡”是出牌阶段限发动一次,那么在没有发动之前它是绿色按钮,发动之后就变成灰色按钮了,需要等待到下一个出牌阶段。
在\ ``条件:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
选牌规则
~~~~~~~~
选牌规则指的是技能按钮按下之后,哪些手牌/装备区的牌可以被选择,哪些不能。“选牌规则”会在玩家每次点击技能按钮,或者点选一张卡牌后,对每张未被选择的卡牌各自进行一次判断,根据判断的结果来确定要不要将卡牌点亮。
在\ ``选牌规则:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
- ``'已选卡牌'``\ :已经被选中的卡牌,类型为卡牌数组。
- ``'备选卡牌'``\ :每一张未被选择的卡牌,类型为卡牌类型。
选目标规则
~~~~~~~~~~
选目标规则指的是,在技能按钮被按下,或者卡牌/目标的被选择状态改变后,对场上的每名角色(包括你自己)分别进行的一次判断。根据判断结果,游戏程序会决定要不要将对应的角色点亮/暗淡。
在\ ``选目标规则:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
- ``'已选目标'``\ :已经被选中的角色,类型为玩家数组。
- ``'备选目标'``\ :每一名未被选择的角色,类型为玩家类型。
- ``'已选卡牌'``\ :已经被选中的卡牌,类型为卡牌数组。在判断目标是否可选时,已选卡牌是判断的必要依据之一。比如“缔盟”就需要选择两名角色的手牌差值等于自己已经选择的卡牌的数量。
可以点确定
~~~~~~~~~~
顾名思义,“可以点确定”指的是技能按钮已经被激活后的某一个时刻下,确定按钮能否被点击。
在\ ``可以点确定:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
- ``'已选目标'``\ :已经被选中的角色,类型为玩家数组。
- ``'已选卡牌'``\ :已经被选中的卡牌,类型为卡牌数组。
使用后
~~~~~~
使用后,自然就是技能本身的效果了。玩家可以在这里编写自己想要执行的种种代码。
在\ ``使用后:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
- ``'选择的目标'``\ :已经被选中的角色,类型为玩家数组。
- ``'选择的卡牌'``\ :已经被选中的卡牌,类型为卡牌数组。
为什么和前面的不太相同,这个我也不太懂 = =
有一点需要注意的是,在技能效果中,用来发动技能的卡牌不会被自动弃置掉。可以使用动作语句“因发动技能而弃牌”去手动选择弃掉的卡牌数量。
主动技中部分判断的局限性
------------------------
主动技和触发技不同有一部分判断是在玩家的视角下进行的而非像触发技那样全知全能。也就是说如果你试图在“选目标规则”中判断目标的身份时游戏可能会对你报错。同样的在自己视角下也不能执行摸牌、回血之类的动作尽管fkparse不会给你指出来。
| 其实就是ServerPlayer和ClientPlayer的区别懒得展开说了
| (记住在除了“使用后”的其他代码块里面别去做一些奇怪的事情就行,到时候写个附录)
主动技和触发技同时使用
----------------------
有些技能既有主动部分也有被动部分,对于这样的技能,可以在技能下面同时定义触发技和主动技。参见示例文本。

View File

@ -1,64 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
基本语法
========
这一章节介绍fkparse语言的基本语法。
注释
----
fkparse支持用下面的格式注释
::
注:
在“注:”后面直到这一行结束的所有内容都会被视为注释,也就是被编译器忽略掉。(注意一下,这里的冒号是全角的冒号)
| fkparse还支持C++和Lua风格的注释。也就是说“//”和“–”后直到行末尾的内容也都被视为注释。
| 此外,还有几个词语也会被编译器忽略:\ *然后、立即*\ 、中文的逗号和句号、Tab、空格、换行。毕竟“然后”和“立即”两个词语确实没啥意义除了便于阅读之外。这意味着你可以随意滥用这两个词反正会被忽略掉
标识符
------
标识符用来标识变量、函数。一个标识符是一串用一对单引号括起来的文本,它可以包含任意字符。比如\ ``'zy','犯大吴疆土者'``\ 都是合法的标识符。
顺便一提,\ ``'你'、'X'``\ 这两个标识符由于使用很频繁,在使用它们的时候无需打单引号。
此外符合C语言标识符语法以下划线或者字母开头后面跟随数个数字或者字母或者下划线的符号也被视为标识符这个也不需要打单引号。
标识符需要通过\ *赋值语句*\ 来定义。有关语句相关的东西我们后面再说。当然fkparse也内置了许多跟游戏概念相关的标识符供用户使用具体见参考手册。
字符串
------
字符串是一串用一对双引号括起来的文本。
数据类型
--------
fkparse定义了以下几种数据类型
- 无类型
- 数字类型
- 布尔类型(真、假)
- 字符串类型
- 玩家类型
- 卡牌类型
- 数组
这些东西无需过多操心,看一下就行了。
代码块
------
代码块仅仅只是一大堆语句罢了。
下一章来讨论fkparse所支持的语句。

View File

@ -1,49 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
创建武将
========
.. _创建武将-1:
创建武将
--------
| 创建武将的格式如下:
::
# <势力> <字符串> <标识符> <数字> [<性别>] <字符串数组>
这一行可以创建一名武将。结合上一章的经验,我们可以知道,创建武将时需要先用“#”开头,然后输入武将的势力、称号、名字、体力上限,最后还输入了一对方括号。
首先是势力。势力只能从\ *魏蜀吴群神*\ 这五个字中进行选择,并且不需要加引号。然后是武将的称号,在上面的格式里面是显示为“<字符串>”,其实就是用一对双引号包括起来的一段文本。接下来是武将的名称,是一个<标识符>,标识符是用单引号包括的文本。再接下来是武将的体力值,这里填一个数字。
再然后就是前面没有填过的几项了武将的性别和内部id。这两项可以不填。这里顺便提一下描述格式时使用的描述方法
- **被尖括号(<>)包括的部分**\ :表示一个概念而不是那个文本自身。
- **被方括号([])包括的部分**\ :表示这个部分是可有可无的。
- **被花括号({})包括的部分**\ :表示这个部分可以不填,也可以填许多个。
- 其他的就是原文照抄了。
回到创建武将的格式上,下面是“性别”这一栏。前面我们创建猪八戒的时候没有填性别,可以看出程序默认为男性武将了。性别有三个可选的选项:\ *男性、女性、中性*\ 。(中性这一项真的有必要存在吗=
=
| 最后那个方括号表示的就是武将的技能了。现在我们还没有开始写技能,所以就让它留空吧。
| 说了这么一堆,似乎给人很复杂的印象了,其实这个还是很简单的。下面给出一些例子:
::
# 神 "----" '观世音' 3 女性 []
# 吴 "整军经武" '谋徐盛' 4 男性 []
| 上面的例子创建了两名新武将。
制作武将的音画素材
------------------
首先一个武将一共有4个素材卡图、全身图、头图、阵亡语音。
(摸鱼了,请参考示例素材罢)

View File

@ -1,78 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
创建技能
========
先来创建一个简单的技能
----------------------
只能制作白板武将的话这个工具的意义就不大了。制作各种各样的技能才是fkparse的最主要的功能。
由于技能和武将是独立的但需要依附拓展包而存在所以fkparse中规定技能的定义必须放在某个拓展包定义的后面。
现在打开study.txt在第一个拓展包的后面起一个新行然后输入以下内容
::
$ '吃苦' "锁定技,你受到伤害后,摸一张牌。" 锁定技
触发技
时机:受到伤害后
效果:你摸1张牌
以上
这样就创建了一个名为“吃苦”的技能。但是光有技能还不行,还得有武将拥有这个技能,不然意义就不大啦。
接下来去我们创建猪八戒的那一行,修改一下,让他获得新技能:
::
# 神 "净坛使者" '猪八戒' 24 ["吃苦"]
现在的study.txt应该像这样保存一下然后生成lua代码吧。
::
拓展包 '学习包1'
$ '吃苦' "锁定技,你受到伤害后,摸一张牌。" 锁定技
触发技
时机:受到伤害后
效果:你摸1张牌
以上
# 神 "净坛使者" '猪八戒' 24 ["吃苦"]
# 神 "----" '观世音' 3 女性 []
# 吴 "整军经武" '谋徐盛' 4 男性 []
拓展包 '学习包2'
创建技能的一般格式
------------------
创建技能的格式如下:
::
$ <标识符> <字符串> [<技能频率>] <技能主体内容> 以上
其中,<标识符>是技能名字,<字符串>是技能描述。技能频率可填可不填。
所谓技能的发动频率,就是锁定技、限定技之类的标签而已。技能频率有以下五种取值:\ *普通技、锁定技、默认技、觉醒技、限定技*\ 。普通技就是普通的技能,而所谓默认技就是在询问发动时直接默认发动(比如枭姬、奸雄之类的技能)。
剩下最重要的部分就是技能的主体内容了。正如前面所示单纯写个技能描述是不能达到制作新技能的目的的。我们需要按照一定的语法规范去编写技能的主体内容才能让fkparse生成相应的技能代码。
**技能主体内容**\ 又分为这几大类型:触发型技能、主动型技能、状态型技能。
触发型技能
----------
触发型技能的创建格式如下:
::
触发技 时机:<时机> [条件:<代码块>] 效果:<代码块>
{时机:<时机> [条件:<代码块>] 效果:<代码块>}
首先以“触发技”三个字开头之后跟上许多时机和效果这就是触发技的创建方法。fkparse支持的时机有许多种在用户指南部分我们不一一罗列后面会列出所有时机的。现在只需要知道示例里面的时机即可。
| 然后是技能的触发条件。这个可以不填,它的默认处理方法是判断当前时机的角色是不是玩家,以及玩家是否拥有本技能。我们直接来看技能的效果吧。效果后面跟的是<代码块>也就是说我们要开始“编程”了用fkparse和我们自己能看懂的方式。代码块并不难看懂比如我们前面写过的一句代码“你摸1张牌”这个一看字面就知道是什么意思啦。
| 接下来的几章会结合实例详细介绍fkparse能接受的代码格式。

View File

@ -1,233 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
表达式和语句
============
要讨论语句,自然避免不了表达式了。我们先来看看表达式。
表达式
------
表达式用来产生一个值。它可能本身就是一个值,也可能是值与值之间进行加减之类的运算,也可能是执行一个动作获得返回值之类的。
数值型表达式
~~~~~~~~~~~~
数值型表达式,说白了就是一个值。它具体又分为这几种类型:
布尔型
^^^^^^
布尔型就是\ *真、假*\ 这两个字。实践表明这两个字几乎不会被用到。
数量型
^^^^^^
一个整数比如1376之类的。很遗憾只能是整数但三国杀里面也基本用不着小数来着。
字符串型
^^^^^^^^
一个字符串。
变量
^^^^
一个变量。关于变量,将在下一节进行讨论。
数组
^^^^
跟C语言的数组的格式差不多fkparse中数组的格式为
::
'[' [<表达式> {,<表达式>}] ']'
一对\ **半角**\ 方括号,中间是零个或者多个表达式。如果是多个的话,中间要有逗号隔开。
这里说明一下fkparse的数组里面所有成员的类型必须相同否则就报错。
字典
^^^^
如同Python里面的字典那样fkparse也支持字典类型而且字典的取值相当自由。其格式为
::
'{' {<字符串> ':' <表达式> ','} '}'
运算型表达式
~~~~~~~~~~~~
表达式之间支持各种运算。
四则运算
^^^^^^^^
加减乘除四种运算,对应的符号分别是\ *+、-、\*、/*\ 。比如2+35*3等等。
这个运算要求两个参与运算的表达式都必须是数字类型。运算结果也为数字类型。
比较运算
^^^^^^^^
可以对两个数字类型的表达式作比较运算,有以下几种运算符。
- *大于*\ :判断前一个是否大于后一个
- *小于*\ :判断前一个是否小于后一个
- *不是*\ :判断两个表达式是否不相等。这个运算符对两侧的表达式没有类型要求
- *是*\ :判断两个表达式是否相等。这个运算符对两侧的表达式没有类型要求
- *不小于*\ :判断前一个是否不小于后一个
- *不大于*\ :判断前一个是否不大于后一个
运算的结果为布尔类型。运算符直接就是汉字使用例2大于3。
这些运算符也可以直接按照C与Lua风格书写\ ``>, <, !=(或者~=), ==, >=, <=``
逻辑运算
^^^^^^^^
两个布尔类型的表达式可以进行逻辑运算。运算符如下:
- *且*\ :若两个都是真,则结果为真,否则结果为假
- *或*\ :只要其中有一个是真,则结果为真;若两者都为假,则结果为假
运算的结果为布尔类型。
运算符就是对应的汉字本身或者也可以按照C风格和Lua风格&&(and), \||(or)
函数调用
~~~~~~~~
详见函数调用那一章。
动作语句表达式
~~~~~~~~~~~~~~
光有上面几种还无法取得所有想要的值,有时候还需要借助动作语句的力量。
动作语句表达式的格式为:
::
'(' <动作语句> ')'
| 也就是用一对圆括号括起来的动作语句。有关动作语句的详情,稍后会进行描述。
| 接下来介绍变量。
.. _变量-1:
变量
----
变量有三种形式:
#. ``<标识符>``\ 。一般是先通过赋值语句定义,然后再进行使用。
#. ``<标识符> 的 <字符串>``\ 。用来获得<标识符>对应的那个变量的某一个属性,比如获得卡牌的花色点数之类的。有关于属性列表的信息,可以在参考手册部分找到,这里不罗列。
#. ``'(' <表达式> ')' 的 <字符串>``\ 。有时候需要获得属性的是一个表达式,此时需要把表达式用括号括起来。
所有的变量都需要定义后使用,但预定义好了的除外。预定义变量又分为两种:
#. 全局有效的预定义变量,不能重新赋值
#. 根据触发时机而确定的跟相关时机有关的变量,可以重新赋值。(但只有某些时机时候重新赋值才有效)比如\ ``'伤害来源'``\ 。
语句
----
表达式用来产生值,而语句则是具体执行的操作。
赋值语句
~~~~~~~~
赋值语句的格式为:
::
令 <变量> 为 <表达式>
或者
::
<变量> 为 <表达式>
这个语句通常用来定义变量,也可以改变变量的值。比如\ ``令'Y'为3``\ 就是一个合法的赋值语句。
注意你不能对系统内置的变量进行重新赋值否则会报错。如果赋值的变量是形如“xx的xx”这种格式的话fkparse可能检测不出错误但这种行为生成的代码可能会无法正常执行。
判断语句
~~~~~~~~
if语句在几乎任何语言里面都有fkparse也不例外判断语句的格式为
::
若 <表达式> 则 <语句块> { 否则若 <表达式> 则 <语句块> } [否则 <语句块>] 以上
循环语句
~~~~~~~~
循环语句的格式如下:
::
重复此流程: <语句块> 直到 <表达式>
这种循环语句是先把语句块执行一遍再判断表达式若表达式条件成立就退出循环。fkp还支持while循环
::
当 <表达式> 重复此流程: <语句块> 以上
这种循环语句会先对表达式进行判断,如果成立的话就执行语句块,然后再判断表达式的值,如此循环,直到表达式不成立为止。
break语句
~~~~~~~~~
break语句用来中止一个循环其格式为
::
中止此流程
请确保自己只在循环语句的内部使用这个fkparse不会去检查的。如果你在别的地方使用的话生成的lua会导致游戏无法启动哦。
返回语句
~~~~~~~~
返回语句用来让函数带上一个返回值,格式为:
::
返回 <表达式>
这个语句只在定义函数的时候用得到,关于函数定义在后续章节中有讲到。
.. _函数调用-1:
函数调用
~~~~~~~~
详见函数那一章。
数组操作
~~~~~~~~
详见后文。
动作语句
~~~~~~~~
终于到所有语句中的重头戏——动作语句了。动作语句用来执行一个实际的动作,比如摸牌、打伤害之类的,有些动作语句还能产生值。
但是由于动作语句的类型太多了,在这里罗列不太现实。请各位去查看参考手册吧。

View File

@ -1,143 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
函数定义和调用,以及数组
========================
fkparse多少也算一门编程语言了或许因此对函数的支持自然也必不可少。本章向大家介绍在使用fkparse时如何定义和调用自己的函数。
定义函数
--------
所谓函数,其实就是一段给定了一些前提条件(也就是函数参数)的代码块而已。通过定义函数,我们少写许多重复的代码。在三国杀这个体系中,“函数”大约就相当于“定义新概念”吧。三国杀也是通过定义一堆新概念来减少描述字数的,虽然搞得有点儿难懂=
=
fkparse中定义一个函数的格式如下
::
定义函数 <标识符> <定义参数表> [返回 <类型标识符>] <代码块>
定义函数的位置也有讲究,所有的函数必须定义在第一个技能之前,也就是说所有的函数都定义完成后才能开始自定义技能。
这里我们又遇到了两个没有见过的新东西:\ ``<参数表>``\ 和\ ``<类型标识符>``\ 。下面一起来看看吧。
类型标识符
~~~~~~~~~~
类型标识符是一个词法单元,它可以取如下的一些格式:\ *数字类型、布尔类型、字符串类型、玩家类型、卡牌类型、数字数组、字符串数组、玩家数组、卡牌数组*\ 。这些东西都不需要引号,它们用来指定一些变量的类型。
定义参数表
~~~~~~~~~~
所谓定义参数表,就是函数定义的时候用到的参数表,这个取名主要是为了和“调用参数表”区分开来。(至于调用参数表又是啥,后面就知道了)
定义\ ``<定义参数表>``\ 的格式如下:
::
'(' { <定义参数> ',' } [定义参数] ')'
而\ ``<定义参数>``\ 的格式为:
::
<标识符> ':' <类型标识符> [ '=' <表达式> ]
<标识符>是参数的名称,<类型标识符>表示这个参数需要的类型。后面的<表达式>表示这个参数的默认值。
定义好定义参数表后,函数体(也就是函数定义的格式的那个<代码块>)就可以随意将参数当做已经定义了的变量使用了,类似其他编程语言那样。
如果函数有返回类型,那么别忘记在某处使用返回语句。
调用函数
--------
定义了函数后,自然还有函数的调用了。调用函数的格式为:
::
<标识符> <参数表>
参数表
~~~~~~
相对于定义参数表,调用函数时候的参数表格式为:
::
'(' { <参数> ',' } [参数] ')'
参数的格式为:
::
<标识符> ':' <表达式>
<标识符>是对应于函数定义那里的那个参数的名字,<表达式>则是参数的取值。
需要注意的是,在调用函数时的参数表中,各个参数没有顺序要求(毕竟已经指明参数的名字了),但是对于没有默认值的参数,必须手动给它指定值。
由于函数调用既能用来执行一些动作,又能产生值,所以它既可以作为表达式,又可以作为语句。但是当单独的函数调用作为语句的时候,需要在后面跟上一个分号,表示这是一个单独的语句。
对数组的操作
------------
fkparse提供了数组类型那自然必不可少的就是数组的操作了。
遍历
~~~~
所谓遍历数组,就是对数组中每个元素逐个进行某些操作。比如想要做到“对所有其他角色各造成一点伤害”,但是造成伤害的语句只允许对一个人造成伤害,这时候我们就需要遍历“其他角色”这个数组,然后一一造成伤害了。
遍历数组的格式为:
::
对 <表达式> 中每个 <标识符> 重复此流程: <代码块> 以上
其中,<表达式>是需要遍历的数组,必须为数组类型;<标识符>表示数组中正在被遍历的那个元素,可以在接下来的代码块中作为变量使用;<代码块>是循环体,也就是前面说的“某种操作”。
插入元素
~~~~~~~~
fkparse支持对数组的头部和尾部插入新元素。
从头部插入的语法为:
::
向 <表达式> 插入 <表达式>
从尾部插入的语法为:
::
向 <表达式> 追加 <表达式>
上面两个语法中,第一个<表达式>是被操作的数组,第二个表达式是要插入的元素。元素必须符合数组的类型才行。
删除元素
~~~~~~~~
fkparse支持删除数组中的某个元素。格式为
::
从 <表达式> 删除 <表达式>
上面两个语法中,第一个<表达式>是被操作的数组,第二个表达式是要删除的元素。
遍历、插入、删除这三个操作可以作为语句使用。
获得数组的信息
~~~~~~~~~~~~~~
fkparse支持获得数组的长度以及根据数组下标取得元素。这两个操作可以作为表达式使用。
要获得长度的话,直接’数组’的"长度"这样就行了。根据下标取得元素的格式为:
::
<表达式> 第 <表达式> 个元素
数组的下标从1开始。

View File

@ -1,66 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
开始使用
========
FreeKill自带fkp模块。
编译运行示例文件
----------------
(请无视这一节内容,过时了)
首先打开fkparse_qt.exe看到如下界面补个插图
然后先点击Choose
File...选择example文件夹下面的example.txt然后点击Compile按钮进行编译。如果编译出错错误将出现在下方否则下面会告诉你编译成功了。
编译成功后点击一下Pack按钮程序就会自动整合所有素材然后在输入的txt的所在文件夹下面生成一个新的文件夹。将新文件夹下面的四个文件夹直接复制到太阳神三国杀的根目录下面然后启动神杀即可。
至此你已经知道如何使用fkparse了接下来说明example.txt这种文件所要求的语法格式。
编写自己的第一个拓展文件
------------------------
首先新建一个文本文件就起名为study.txt吧。在之后的部分都将基于这个文件进行操作。打开study.txt用记事本或者代码编辑器之类的东西都可。
创建拓展包
~~~~~~~~~~
TODO
| 拓展文件首先要从创建拓展包开始。fkparse中创建拓展包的格式为
| *拓展包 <标识符>*
| “标识符”就是用单引号括起来的文本,毕竟中文不用空格进行分词。一个拓展文件中可以含有多个拓展包,下面我们来创建两个空拓展包:
::
拓展包 '学习包1'
拓展包 '学习包2'
保存然后用它去生成study.lua。将study.lua放入extensions里面你应该能在游戏中看到这两个拓展包了。
创建武将
~~~~~~~~
创建武将的详细的内容在下一章说明。这里我们只是简单的新建一个武将而已。
现在我们要创建一个武将它所属于学习包1名字是猪八戒称号是净坛使者神势力24体力。那么我们现在在“拓展包
学习包1”下面另起一个新行然后输入
::
# 神 "净坛使者" '猪八戒' 24 []
这一段话的详细内容下一章再细说。现在保存文件然后重新生成lua。现在你的study.txt的内容应该是像这样
::
拓展包 '学习包1'
# 神 "净坛使者" '猪八戒' 24 []
拓展包 '学习包2'
错误处理
--------
如果编译出错,错误信息将显示在窗口内部。请根据报错信息仔细检查出错或者咨询作者吧。

View File

@ -1,18 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
FKP用户指南
===========
.. toctree::
:maxdepth: 1
intro.rst
get_started.rst
create_general.rst
create_skill.rst
basic_grammar.rst
exp_stat.rst
func_array.rst
active_skill.rst
viewas_skill.rst
status_skill.rst

View File

@ -1,16 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
fkparse简介
===========
fkparse是借助Flex和Bison用C语言编写的太阳神三国杀Lua生成器。它能分析按照语法规定编写的三国杀拓展文本并根据这个生成可以在太阳神三国杀上运行的武将技能代码。
| 目前仍处于开发早期阶段...
| 这个手册分为三大板块,每个板块又分为几个章节。
第一部分是用户指南旨在让用户快速了解fkp的用途
- 开始使用下载和运行fkparse
第二部分是参考手册它详细的介绍了fkp语言支持的所有功能。
第三部分是开发者文档它向开发者大致介绍了fkp的实现以及如何拓展fkp的功能。

View File

@ -1,102 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
状态技
======
最后一种技能类型:状态技。所谓状态技就是那种既不被动也不主动就能产生影响的技能。所有的状态技都是全局生效的。
创建一个状态技的格式为:
::
状态技
[禁止指定目标:<代码块>]
[选牌规则:<代码块> 视为规则:<代码块>]
[距离修正:<代码块>]
[手牌上限修正:<代码块>]
[手牌上限固定:<代码块>]
[出牌次数修正:<代码块>]
[出牌距离修正:<代码块>]
[出牌目标数量修正:<代码块>]
[攻击范围修正:<代码块>]
[攻击范围固定:<代码块>]
可以看出,除了“状态技”三个字之外,所有的都是可选的要素,但语法规定至少要有一个可选要素。这些可选要素又分为许多个大类,具体为以下几种:
卡牌禁止类
----------
卡牌禁止类就是让某人不能成为某种卡牌的目标,比如空城、帷幕等技能。(注意这与毅重这种令卡牌无效的技能有本质区别)
控制这种东西的代码块是\ ``禁止指定目标:``\ 之后的。在这个代码块中,你可以使用以下的预定义变量:
- ``'目标'``\ :可能成为这张卡牌的目标的玩家。
- ``'来源'``\ :可能打算使用这张卡牌的玩家。
- ``'卡牌'``\ :可能会被使用的卡牌。
在这个代码块中返回真的话,那么就意味着这个目标被禁止成为来源使用此牌的目标。
注意,你不能在这个代码块中使用预定义变量“你”。这是因为,每当某人将手牌区的牌点亮后,禁止技就会在此时发挥作用,也就是说禁止技对所有人皆有效。
锁定视为类
----------
锁定视为就是像红颜这样的技能,某一类卡牌直接被视为另一种卡牌。
控制锁定视为的代码块是\ ``选牌规则:``\ 和\ ``视为规则:``\ 这两种。二者缺一不可。
在这两个代码块中,你都可以使用以下的预定义变量:
- ````\ :玩家自己。
- ``'备选卡牌'``\ :每一张未被选择的卡牌,类型为卡牌类型。
注意到预定义变量只剩两个了。这是因为锁定视为技一次只会影响到一张牌,没有像“锁定技,你的两张杀均视为桃。”这种不合理的锁定视为技存在。
距离修改类
----------
这种技能指的是像马术、飞影这样影响距离计算的技能。
控制其代码块是\ ``距离修正:``\ 之后的。在这个代码块中,你可以使用以下的预定义变量:
- ``'目标'``\ :位于本次距离计算终点的玩家。
- ``'来源'``\ :位于本次距离计算起点的玩家。
在这个函数中返回正数的话,就会导致来源到目标计算距离增加相应的数值。同理,返回负数的话,会导致来源到目标计算距离减少。
手牌上限修改类
--------------
诸如慎拒、界英姿这类能修改手牌上限的技能。
控制锁定视为的代码块是\ ``手牌上限修正:``\ 和\ ``手牌上限固定:``\ 这两种。
在这两个代码块中,你都可以使用以下的预定义变量:
- ``'玩家'``\ :将要计算手牌上限的玩家。
在\ ``手牌上限修正:``\ 中返回正数或负数可以修正手牌上限。另一个中则是直接返回想要的手牌上限。
两个代码块不允许同时存在。如果共存的话,手牌上限固定将会被忽略。
卡牌效果增强类
--------------
诸如咆哮、天义这种能打破规则使用卡牌的技能。
控制卡牌增强的代码块是\ ``出牌次数修正:``\ 、\ ``出牌距离修正:``\ 、\ ``出牌目标数量修正:``\ 。根据返回值,第一个影响出牌次数限制,第二个影响出牌距离限制,第三个影响这张牌能选择的最大目标数量。
在这些代码块中能使用以下预定义变量:
- ``'玩家'``\ :将要使用此牌的玩家。
- ``'卡牌'``\ :将要使用的卡牌。
攻击范围修改类
--------------
和修改手牌上限一样,区别就是这个修改的是攻击范围。

View File

@ -1,3 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later

View File

@ -1,82 +0,0 @@
.. SPDX-License-Identifier: GFDL-1.3-or-later
视为技能
========
视为技能概述
------------
视为技就是把一张或者好几张牌当某张其他牌使用的技能,比如武圣倾国等等,但不包括奇策这种。
在fkparse中创建视为技能的语法格式为
::
视为技 条件:<代码块> 选牌规则:<代码块> 可以点确定:<代码块>
视为规则:<代码块> [ 响应条件:<代码块> 响应规则:<字符串数组> ]
可以看出,视为技的创建格式和主动技十分相似。事实上,由于某些原因,视为技和主动技是冲突的,不能同时存在同一个技能下面。如果同时存在的话,则只有主动技会起作用。
下面来一一叙述各个\ ``代码块``\ 的意义。
条件
~~~~
条件指的是视为技在出牌阶段的空闲时间点能不能被使用。更加确切的说,“条件”是指技能按钮需要被点亮的一系列条件,如果这些条件不能满足的话,技能按钮就会显示为灰色。例如技能“倾国”是把黑牌当闪用,那么自然就不能在出牌阶段主动使用了。
在\ ``条件:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
选牌规则
~~~~~~~~
选牌规则指的是技能按钮按下之后,哪些手牌/装备区的牌可以被选择,哪些不能。“选牌规则”会在玩家每次点击技能按钮,或者点选一张卡牌后,对每张未被选择的卡牌各自进行一次判断,根据判断的结果来确定要不要将卡牌点亮。
在\ ``选牌规则:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
- ``'已选卡牌'``\ :已经被选中的卡牌,类型为卡牌数组。
- ``'备选卡牌'``\ :每一张未被选择的卡牌,类型为卡牌类型。
可以点确定
~~~~~~~~~~
顾名思义,“可以点确定”指的是技能按钮已经被激活后的某一个时刻下,确定按钮能否被点击。实际上,视为技必须要先通过“可以点确定”的检测,才会去调用“视为规则”去获得转化之后的牌。
在\ ``可以点确定:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
- ``'已选卡牌'``\ :已经被选中的卡牌,类型为卡牌数组。
视为规则
~~~~~~~~
视为规则自然就是想要视为什么牌了。玩家可以在这里编写各种控制结构之类的,最后返回一张虚拟牌即可。
关于如何返回虚拟牌,可以参见“所有的预定义函数”一章,或者直接看示例。
在\ ``视为规则:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
- ``'选择的卡牌'``\ :已经被选中的卡牌,类型为卡牌数组。
为什么和前面的不太相同,这个我也不太懂 = =
响应条件
~~~~~~~~
与主动技不同,视为技转化的卡牌有些是可以在响应时被使用或者打出的。而“响应条件”自然就是判断能否响应了。一般也就判断一下隐藏标记之类的吧,或者自己有没有牌之类的(防烧条,然而现在没法判断自己是不是没牌)
在\ ``响应条件:``\ 后面跟随的\ ``<代码块>``\ 中,玩家可以使用以下预定义的变量名:
- ````\ :玩家自己。
响应规则
~~~~~~~~
响应规则是一个字符串数组,表示这个视为技可以响应的所有牌的类型。你可以简单的只写个牌名上去,也可以通过\ ``'创建卡牌规则'``\ 函数创造出相当复杂的响应规则。

View File

@ -16,6 +16,3 @@
inner/index.rst inner/index.rst
dev/index.rst dev/index.rst
api/index.rst api/index.rst
fkp/usr/index.rst
fkp/ref/index.rst
fkp/dev/index.rst

@ -1 +0,0 @@
Subproject commit fd7023f0752bfaa6fc5230ef1b1835eb4dfefe2f

View File

@ -1,7 +1,6 @@
-- SPDX-License-Identifier: GPL-3.0-or-later -- SPDX-License-Identifier: GPL-3.0-or-later
local fkp_extensions = require "packages.test.test" local extension = Package("test_p_0")
local extension = fkp_extensions[1]
local cheat = fk.CreateActiveSkill{ local cheat = fk.CreateActiveSkill{
name = "cheat", name = "cheat",
@ -147,6 +146,7 @@ test2:addSkill(test_vs)
test2:addSkill(test_trig) test2:addSkill(test_trig)
Fk:loadTranslationTable{ Fk:loadTranslationTable{
["test_p_0"] = "测试包",
["test"] = "测试", ["test"] = "测试",
["test_filter"] = "破军", ["test_filter"] = "破军",
[":test_filter"] = "你的点数大于11的牌视为无中生有。", [":test_filter"] = "你的点数大于11的牌视为无中生有。",
@ -155,4 +155,4 @@ Fk:loadTranslationTable{
[":cheat"] = "出牌阶段,你可以获得一张想要的牌。", [":cheat"] = "出牌阶段,你可以获得一张想要的牌。",
} }
return fkp_extensions return { extension }

View File

@ -1,35 +0,0 @@
拓展包 '测试包'
$ '伤摸' "你造成伤害后可以摸5张牌。"
触发技
时机:造成伤害后
效果你摸5张牌 你对伤害目标造成3点伤害
以上
$ '苦肉' “你可以失去一点体力摸3张牌”
主动技
条件:返回真
选牌规则:返回假
选目标规则:返回假
可以点确定:返回真
使用后你失去1点体力你摸3张牌
以上
$ '倾国' "可以将牌当决斗使用打出"
视为技
条件: 返回真
选牌规则: 若'已选卡牌'."长度"是0则返回真以上。
可以点确定: 若'已选卡牌'."长度"是1则返回真以上。
视为规则: 返回'创建虚拟牌'(0, '无花色', '决斗', '选择的卡牌', "倾国")
响应条件: 返回真
响应规则: [ '决斗' ]
以上
$ '生有' “你的小于4的牌视为无中生有”
状态技
选牌规则:返回'备选卡牌'."点数" < 4
视为规则:返回‘创建虚拟牌’('备选卡牌'."点数", '备选卡牌'."花色", '无中生有')
出牌次数修正:若‘卡牌’.“牌名”是'杀'则返回999以上
end
# 魏 "大魏吴王" '魏孙权' 4 [ "伤摸", "苦肉", "倾国", "生有" ]

View File

@ -4,7 +4,6 @@ set(freekill_SRCS
"main.cpp" "main.cpp"
"core/player.cpp" "core/player.cpp"
"core/util.cpp" "core/util.cpp"
"core/parser.cpp"
"core/packman.cpp" "core/packman.cpp"
"network/server_socket.cpp" "network/server_socket.cpp"
"network/client_socket.cpp" "network/client_socket.cpp"
@ -23,7 +22,6 @@ if (NOT DEFINED FK_SERVER_ONLY)
) )
endif () endif ()
set(FKP_LIB fkparse)
set(QT_LIB set(QT_LIB
Qt6::Network Qt6::Network
) )
@ -88,11 +86,9 @@ target_link_libraries(FreeKill PRIVATE
${CRYPTO_LIB} ${CRYPTO_LIB}
${SSL_LIB} ${SSL_LIB}
${READLINE_LIB} ${READLINE_LIB}
${FKP_LIB}
${QT_LIB} ${QT_LIB}
${GIT_LIB} ${GIT_LIB}
${IDBFS_LIB} ${IDBFS_LIB}
) )
install(TARGETS FreeKill DESTINATION bin) install(TARGETS FreeKill DESTINATION bin)
install(TARGETS fkparse DESTINATION lib)

View File

@ -3,7 +3,6 @@
#include "client.h" #include "client.h"
#include "client_socket.h" #include "client_socket.h"
#include "clientplayer.h" #include "clientplayer.h"
#include "parser.h"
#include "util.h" #include "util.h"
Client *ClientInstance; Client *ClientInstance;
@ -21,8 +20,6 @@ Client::Client(QObject *parent) : QObject(parent), callback(0) {
connect(socket, &ClientSocket::error_message, this, &Client::error_message); connect(socket, &ClientSocket::error_message, this, &Client::error_message);
router = new Router(this, socket, Router::TYPE_CLIENT); router = new Router(this, socket, Router::TYPE_CLIENT);
Parser::parseFkp();
L = CreateLuaState(); L = CreateLuaState();
DoLuaScript(L, "lua/freekill.lua"); DoLuaScript(L, "lua/freekill.lua");
DoLuaScript(L, "lua/client/client.lua"); DoLuaScript(L, "lua/client/client.lua");

View File

@ -1,97 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "parser.h"
static Parser *p = nullptr;
Parser::Parser() { parser = fkp_new_parser(); }
Parser::~Parser() { fkp_close(parser); }
int Parser::parse(const QString &fileName) {
if (!QFile::exists(fileName)) {
return 1;
}
QString cwd = QDir::currentPath();
QStringList strlist = fileName.split('/');
QString shortFileName = strlist.last();
strlist.removeLast();
QString path = strlist.join('/');
QDir::setCurrent(path);
auto fnamebytes = shortFileName.toUtf8();
bool error = fkp_parse(parser, fnamebytes.constData(), FKP_FK_LUA);
if (error) {
QStringList tmplist = shortFileName.split('.');
tmplist.removeLast();
QString fName = tmplist.join('.') + "-error.txt";
if (!QFile::exists(fName)) {
qCritical("FKP parse error: Unknown error.");
} else {
QFile f(fName);
f.open(QIODevice::ReadOnly);
qCritical() << "FKP parse error:\n" << f.readAll().constData();
f.remove();
}
}
QDir::setCurrent(cwd);
return error;
}
static QStringList findFile(const QString &path, const QString &filename) {
QStringList ret;
if (path.isEmpty() || filename.isEmpty()) {
return ret;
}
QDir dir;
QStringList filters;
filters << filename;
dir.setPath(path);
dir.setNameFilters(filters);
QDirIterator iter(dir, QDirIterator::Subdirectories);
while (iter.hasNext()) {
iter.next();
auto info = iter.fileInfo();
if (info.isFile()) {
ret.append(info.absoluteFilePath());
} else if (info.isDir()) {
ret.append(findFile(path, filename));
}
}
return ret;
}
void Parser::parseFkp() {
if (!p) {
p = new Parser;
}
foreach (QString s, findFile("./packages", "*.fkp")) {
p->parse(s);
}
}
#ifndef Q_OS_WASM
static void copyFkpHash2QHash(QHash<QString, QString> &dst, fkp_hash *from) {
dst.clear();
for (size_t i = 0; i < from->capacity; i++) {
if (from->entries[i].key != NULL) {
dst[from->entries[i].key] = QString((const char *)from->entries[i].value);
}
}
}
void Parser::readHashFromParser() {
copyFkpHash2QHash(generals, parser->generals);
copyFkpHash2QHash(skills, parser->skills);
copyFkpHash2QHash(marks, parser->marks);
}
#endif

View File

@ -1,24 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#ifndef _PARSER_H
#define _PARSER_H
#include "fkparse.h"
class Parser {
public:
Parser();
~Parser();
int parse(const QString &filename);
static void parseFkp();
private:
fkp_parser *parser;
QHash<QString, QString> generals;
QHash<QString, QString> skills;
QHash<QString, QString> marks;
void readHashFromParser();
};
#endif

View File

@ -9,7 +9,6 @@
#include "client_socket.h" #include "client_socket.h"
#include "packman.h" #include "packman.h"
#include "parser.h"
#include "player.h" #include "player.h"
#include "room.h" #include "room.h"
#include "router.h" #include "router.h"
@ -27,7 +26,6 @@ Server::Server(QObject *parent) : QObject(parent) {
file.open(QIODevice::ReadOnly); file.open(QIODevice::ReadOnly);
QTextStream in(&file); QTextStream in(&file);
public_key = in.readAll(); public_key = in.readAll();
Parser::parseFkp();
md5 = calcFileMD5(); md5 = calcFileMD5();
readConfig(); readConfig();