“苏泽学习笔记”的版本间的差异
第92行: | 第92行: | ||
== 运行模式 == | == 运行模式 == | ||
是游戏开始后,执行一次 onPluginStart() | 是游戏开始后,执行一次 onPluginStart(),然后在所有玩家的机器上都循环执行 beforeTriggerExec()、触发器、afterTriggerExec() | ||
例如有如下配置 main.edd: | 例如有如下配置 main.edd: |
2023年4月19日 (三) 14:23的版本
个人学习的理解
epScript、eudplib、euddraft 的关系
epScript 是由 TriggerKing 创造的脚本语言,用于利用星际争霸的触发器的 EUD 漏洞编写复杂的触发器逻辑
eudplib 是一个 Python 库,它提供了一系列可读性较好的编写触发器逻辑的 API,并且运行这些 Python 脚本(*.py
)将会生成对应的星际争霸的触发器字节码
euddraft 先将编写好的 epScript 脚本(*.eps
)编译成调用 eudplib 功能的 Python 脚本(*.py
)
然后 euddraft 会按照一定顺序运行这些 Python 脚本(*.py
),它们将会调用 eudplib 来生成与编写好的 epScript 脚本(*.eps
)等效的实际的触发器字节码
最终 euddraft 再将这些触发器字节码插入地图中,在地图加载时生效,实现逻辑并产生效果
更多细节可参考
如何开始
以下操作,假如有遇到看不懂的地方,可以尝试搜索引擎解决
这里假设你已经会使用 SCMD 进行基本的地形设计,如果还不会,请先参考:
环境准备
准备一台 Windows 10 以上的 PC,或者虚拟机
准备好 SCMD,如果还没准备,往回看几行
- 将 euddraft 解压缩到一个纯英文没有空格的路径中,例如 D:\SCRMapDevTools\euddraft0.9.9.7
下载 VSCode
- 安装它,随便怎么安装都行
- 从 VSCode 插件商店中安装 eps-server 这款插件
地图准备
准备一个普通的地图文件,可以用 SCMD 新建,然后保存成 Starcraft: Remastered Broodwar Map (*.scx) 格式的文件
依然保存到一个纯英文没有空格的路径中,例如 D:\Projects\test\basemap.scx
建立工程
新建一个文本文档,并将它的扩展名改为 edd ,例如 D:\Projects\test\test.edd
- 使用 VSCode 打开这个 edd 文件(直接将文件往打开的 VSCode 界面中一拖就行),然后把它的内容改为
[main] input: basemap.scx output: test.scx [main.eps]
- 以上代码用相对路径做例子,实际它是支持绝对路径的
- 新建一个文本文档,并将它的扩展名改为 eps ,例如
D:\Projects\test\main.eps
- 使用 VSCode 打开这个 eps 文件,然后把它的内容改为
function onPluginStart() { // 游戏开始将会执行一次这个函数 DisplayTextAll("Hello World"); } function beforeTriggerExec() { // 游戏每一帧会先执行一次这个,然后执行传统触发器 } function afterTriggerExec() { // 游戏每一帧在执行完传统触发器后,会执行一次这个函数 }
新建一个文本文档,并将它的扩展名改为 bat ,例如 D:\Projects\test\build.bat
使用 VSCode 打开这个 bat 文件,然后把它的内容改为
D:\SCRMapDevTools\euddraft0.9.9.7\euddraft.exe test.edd
- 以上代码假设你将 euddraft 解压到了
D:\SCRMapDevTools\euddraft0.9.9.7
这个位置,如果它不在这儿,你应该替换它
- 至此,工程就已经建立好了,直接双击运行 build.bat 就可以生成 test.scx,将这个地图放入星际重制版的地图目录中,然后进游戏就能看到它在屏幕上输出的 Hello World
运行模式
是游戏开始后,执行一次 onPluginStart(),然后在所有玩家的机器上都循环执行 beforeTriggerExec()、触发器、afterTriggerExec()
例如有如下配置 main.edd:
[main] input: in.scx output: out.scx [a.eps] [b.eps] [c.eps]
游戏开始后的执行顺序为:
a.onPluginStart() b.onPluginStart() c.onPluginStart() 每帧循环执行: a.beforeTriggerExec() b.beforeTriggerExec() c.beforeTriggerExec() SCMD 触发器 c.afterTriggerExec() b.afterTriggerExec() a.afterTriggerExec()
数据同步说明
如果将`非同步数据`(例如玩家鼠标位置)赋值给变量,该变量对于每个玩家都不一样,若以此判断做出更改`需要同步的数据`的动作,将会导致多人游戏中玩家`需要同步的数据`不同步而引发掉线
该类任务通常可以使用 MSQC 插件来辅助解决
当前玩家与本机玩家
当前玩家
与 本机玩家
是两个不同的概念
当前玩家
即 CurrentPlayer ,是一个全局变量,有一些函数内部会使用它
setcurpl 是设置使用 CurrentPlayer 这个全局变量值的函数
getcurpl 是获取 CurrentPlayer 这个全局变量现在是什么值的函数
无论你将 CurrentPlayer 设置为什么值,所有的代码都会在所有玩家的机器上执行
示例
setcurpl(P1); StringBuffer(64).printf("给玩家 1 打印的内容"); setcurpl(P2); StringBuffer(64).printf("给玩家 2 打印的内容"); setcurpl(P3); StringBuffer(64).printf("给玩家 3 打印的内容");
本机玩家
getuserplayerid() 可以获取 本机玩家编号,它对每个机器都返回不同的值,与 setcurpl 函数设置的值毫无关联
可以使用 getuserplayerid() 来获取本机玩家的编号意味着你可以决定是否在本机执行或者不执行某些代码,当然你需要小心,千万不要试图以此直接或者间接污染`需要同步的数据`,它可能导致数据不同步而引发掉线
示例
setcurpl(P1); StringBuffer(64).printf("当前玩家编号:{}", getuserplayerid()); setcurpl(P2); StringBuffer(64).printf("当前玩家编号:{}", getuserplayerid()); setcurpl(P3); StringBuffer(64).printf("当前玩家编号:{}", getuserplayerid());