苏泽学习笔记

来自星际争霸重制版地图研究所
跳到导航 跳到搜索

个人学习的理解

epScript、eudplib、euddraft 的关系

epScript 是由 TriggerKing 创造的脚本语言,用于利用星际争霸的触发器的 EUD 漏洞编写复杂的触发器逻辑

eudplib 是一个 Python 库,它提供了一系列可读性较好的编写触发器逻辑的 API,并且运行这些 Python 脚本(*.py)将会生成对应的星际争霸的触发器字节码

euddraft 先将编写好的 epScript 脚本(*.eps)编译成调用 eudplib 功能的 Python 脚本(*.py

然后 euddraft 会按照一定顺序运行这些 Python 脚本(*.py),它们将会调用 eudplib 来生成与编写好的 epScript 脚本(*.eps)等效的实际的触发器字节码

最终 euddraft 再将这些触发器字节码插入地图中,在地图加载时生效,实现逻辑并产生效果

更多细节可参考

epScript 实现原理

如何开始

以下操作,假如有遇到看不懂的地方,可以尝试搜索引擎解决

这里假设你已经会使用 SCMD 进行基本的地形设计,如果还不会,请先参考:

SCMD

这里假设你已经知道 EUD 是什么意思,如果还不知道,请先参考:

EUD

环境准备

准备一台 Windows 10 以上的 PC,或者虚拟机

准备好 SCMD,如果还没准备,往回看几行

下载 euddraft0.9.9.7.7z

将 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 插件来辅助解决


当前玩家与本机玩家

当前玩家本机玩家 是两个不同的概念

当前玩家

是一个全局变量,有一些函数内部会使用它,当前玩家甚至可能根本不是指一个玩家,可能存储任何数值

setcurpl 是设置当前玩家这个全局变量值的函数

getcurpl 是获取当前玩家这个全局变量现在是什么值的函数

无论你将当前玩家设置为什么值,所有的代码都会在所有玩家的机器上执行

示例

setcurpl(P1);
StringBuffer(64).printf("给玩家 1 打印的内容");
setcurpl(P2);
StringBuffer(64).printf("给玩家 2 打印的内容");
setcurpl(P3);
StringBuffer(64).printf("给玩家 3 打印的内容");

// CurrentPlayer 是常量数字 13,它可以使一些与玩家相关的条件或动作去访问 当前玩家 的值
// CurrentPlayer != getcurpl()

// 将 Fastest 游戏速度 x2
setcurpl(-122787 + 6);
SetDeaths(CurrentPlayer, SetTo, 21, 0);

本机玩家

getuserplayerid() 可以获取 本机玩家编号,它对每个机器都返回不同的值,与 setcurpl 函数设置的值毫无关联

可以使用 getuserplayerid() 来获取本机玩家的编号意味着你可以决定是否在本机执行或者不执行某些代码,当然你需要小心,千万不要试图以此直接或者间接污染`需要同步的数据`,它可能导致数据不同步而引发掉线

示例

setcurpl(P1);
StringBuffer(64).printf("当前玩家编号:{}", getuserplayerid());
setcurpl(P2); StringBuffer(64).printf("当前玩家编号:{}", getuserplayerid());
setcurpl(P3); StringBuffer(64).printf("当前玩家编号:{}", getuserplayerid());

edd 和 eds 的区别

euddraft 对这两种扩展名的处理方式不一样

对 edd 格式

它会在顺利编译生成地图完成后保持等待,如果项目目录中文件发生了变化,则它会自动再次编译生成地图

如果不顺利,则输出错误信息,你可以按 R 键让它再次编译生成

对 eds 格式

它会在顺利编译生成地图完成后退出

如果不顺利,会输出错误信息并等待你按回车键退出


epScript 文档

基本语法

使用变量

使用函数

使用对象

内置基本对象类型

内置扩展对象类型

常量对照表

内置函数库