内置的基本对象类型
基本对象类型
-
EUDVariable
其实就是 var 声明的那个变量啦,它也是一个对象,只不过它在语法上被定义为值类型,和其它对象类型有一些区别,比如可以用等号赋值等
一个 EUDVariable 将使用一个只有一条 SetDeathsX 动作的虚拟触发器模拟,占用 72 字节,以下是它的类型结构,它有很多条件和动作函数object EUDVariable {
// 常规方法
function ineg(){} // euddraft 0.9.9.8 版新增,将自身值转换为相反数,相当于 x = -x; 支持转换成动作这样用 DoActions(v.ineg(action = true));
function iabs(){} // euddraft 0.9.9.8 版新增,将自身值转换为绝对值,相当于 x = (x & (1 << 31) == 0) ? x : -x; 支持转换成动作这样用 DoActions(v.iabs(action = true));
// 常规条件
function AtLeast(v){} // 变量值 >= v
function AtMost(v){} // 变量值 <= v
function Exactly(v){} // 变量值 == v
function AtLeastX(v,mask){} // (变量值 & mask) >= v
function AtMostX(v,mask){} // (变量值 & mask) <= v
function ExactlyX(v,mask){} // (变量值 & mask) == v
function MaskAtLeast(v){} // 变量的虚拟触发器 SetDeathsX 的动作的 Mask >= v
function MaskAtMost(v){} // 变量的虚拟触发器 SetDeathsX 的动作的 Mask <= v
function MaskExactly(v){} // 变量的虚拟触发器 SetDeathsX 的动作的 Mask == v
function MaskAtLeastX(v,msk){} // 变量的虚拟触发器 SetDeathsX 的动作的 (Mask & msk) >= v
function MaskAtMostX(v,msk){} // 变量的虚拟触发器 SetDeathsX 的动作的 (Mask & msk) <= v
function MaskExactlyX(v,msk){} // 变量的虚拟触发器 SetDeathsX 的动作的 (Mask & msk) == v
// 常规动作
function SetNumber(v){} // 变量值 = v
function AddNumber(v){} // 变量值 = 变量值 + v
function SubtractNumber(v){} // 变量值 = 变量值 - v if 变量值 <= v else 变量值 = 0
function SetNumberX(v,mask){} // 变量值 = 变量值 - (变量值 & mask) + (v & mask)
function AddNumberX(v,mask){} // 变量值 = 变量值 - (变量值 & mask) + ( ((变量值 & mask) + (v & mask)) & mask )
function SubtractNumberX(v,mask){} // 变量值 = 变量值 - (变量值 & mask) + ( ((变量值 & mask) - (v & mask)) & mask )
// 编译期常量函数
function GetVTable(){} // 编译期获取变量虚拟触发器的运行时地址
function getMaskAddr(){} // 编译期获取变量虚拟触发器的 SetDeathsX 动作中的掩码参数的运行时地址
function getValueAddr(){} // 编译期获取变量虚拟触发器的 SetDeathsX 动作中的数值参数的运行时地址
function getDestAddr(){} // 编译期获取变量虚拟触发器的 SetDeathsX 动作中的玩家编号参数的运行时地址
// 下列动作实际只能配合 VProc 使用
function SetMask(v){} // 将变量的虚拟触发器 SetDeathsX 的动作的 Mask = v
function AddMask(v){} // 将变量的虚拟触发器 SetDeathsX 的动作的 Mask = Mask + v
function SubtractMask(v){} // 将变量的虚拟触发器 SetDeathsX 的动作的 Mask = Mask - v if Mask >= v else Mask = 0
function SetMaskX(v,msk){} // 将变量的虚拟触发器 SetDeathsX 的动作的 Mask = Mask - (Mask & msk) + (v & msk)
function AddMaskX(v,msk){} // 将变量的虚拟触发器 SetDeathsX 的动作的 Mask = Mask - (Mask & msk) + ( ((Mask & msk) + (v & msk)) & msk )
function SubtractMaskX(v,msk){} // 将变量的虚拟触发器 SetDeathsX 的动作的 Mask = Mask - (Mask & msk) + ( ((Mask & msk) - (v & msk)) & msk )
function SetDest(dest){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 = dest
function AddDest(dest){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 = 玩家编号 + dest
function SubtractDest(dest){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 = 玩家编号 - dest if 玩家编号 >= dest else 玩家编号 = 0
function SetDestX(dest,mask){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 = 玩家编号 - (玩家编号 & mask) + (dest & mask)
function AddDestX(dest,mask){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 = 玩家编号 - (玩家编号 & mask) + ( ((玩家编号 & mask) + (dest & mask)) & mask )
function SubtractDestX(dest,mask){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 = 玩家编号 - (玩家编号 & mask) + ( ((玩家编号 & mask) - (dest & mask)) & mask )
function SetModifier(modifier){} // 将变量的虚拟触发器 SetDeathsX 的动作的 数值修改方法 设置为 modifier
function QueueAssignTo(dest){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 设置为 dest 并将 数值修改方法 设置为 SetTo
function QueueAddTo(dest){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 设置为 dest 并将 数值修改方法 设置为 Add
function QueueSubtractTo(dest){} // 将变量的虚拟触发器 SetDeathsX 的动作的 玩家编号 设置为 dest 并将 数值修改方法 设置为 Subtract,Subtract 方法无法将数值从正数减到负数
};
-
EUDLightVariable
轻变量,它和 var 声明的变量不同,它仅开辟 4 字节的内存空间,它的传值操作相较于普通变量更消耗资源,判断值或者写入值和普通变量一样仅需要执行一条触发器。(普通变量实质是一个虚拟触发器,占用 72 字节)
要将它的值当作参数传递到其它函数中则需要使用 dwread 函数来读取它。
若一个普通变量(EUDVariable)的值不需要当作其它函数的参数(例如用于计数判断、自增、自减、赋值、开关等不与其它函数/条件/动作关联的场景),则可使用 EUDLightVariable 来替代该普通变量。object EUDLightVariable {
// 编译期常量函数
function getValueAddr(){}
// 能够通过以下函数、条件、动作搭配达成的目标,都可选用 EUDLightVariable 实现,否则就应该用普通变量(EUDVariable)
// 常规方法
function ineg(){} // 将自身值转换为相反数,相当于 x = -x; 在 euddraft 0.9.9.8 及之后的版本中支持转换成动作这样用 DoActions(v.ineg(action = true));
function iabs(){} // euddraft 0.9.9.8 新增,将自身值转换为绝对值,相当于 x = (x & (1 << 31) == 0) ? x : -x; 支持转换成动作这样用 DoActions(v.iabs(action = true));
// 常规条件
function AtLeast(v){} // 轻变量值 >= v
function AtMost(v){} // 轻变量值 <= v
function Exactly(v){} // 轻变量值 == v
function AtLeastX(v,mask){} // (轻变量值 & mask) >= v
function AtMostX(v,mask){} // (轻变量值 & mask) <= v
function ExactlyX(v,mask){} // (轻变量值 & mask) == v
// 常规动作
function SetNumber(v){} // 轻变量值 = v
function AddNumber(v){} // 轻变量值 = 轻变量值 + v
function SubtractNumber(v){} // 轻变量值 = 轻变量值 - v if 轻变量值 <= v else 轻变量值 = 0
function SetNumberX(v,mask){} // 轻变量值 = 轻变量值 - (轻变量值 & mask) + (v & mask)
function AddNumberX(v,mask){} // 轻变量值 = 轻变量值 - (轻变量值 & mask) + ( ((轻变量值 & mask) + (v & mask)) & mask )
function SubtractNumberX(v,mask){} // 轻变量值 = 轻变量值 - (轻变量值 & mask) + ( ((轻变量值 & mask) - (v & mask)) & mask )
};示例
const lv = EUDLightVariable(100);
DoActions(lv.AddNumber(564)); // lv += 564;
if (lv != 150) {
println("{}", dwread(lv.getValueAddr())); // 这个读取值的过程比普通变量要消耗更多的触发器资源,大概在 32 倍以上
}
lv.ineg(); // lv = -lv;
if (lv > 0x80000000 && lv < -663) {
println("小于 -663 的负数");
}
-
EUDLightBool
轻布尔型(开关)变量,它使用最少 1 位(八分之一字节)存储,布尔型变量尽量用这个,而非 var
在 eudplib 内部实现中每 32 个 EUDLightBool 共用一个 EUDLightVariable
布尔型(开关)只能表示两个状态,1 表示 Set,0 表示 Cleared,默认初始值为 Clearedobject EUDLightBool {
// 编译期常量函数
function getValueAddr() {}
// 常规条件
function IsSet(){} // 当前开关为已设置状态
function IsCleared(){} // 当前开关为已清除状态
// 常规动作
function Set(){} // 设置为开状态
function Clear(){} // 设置为关状态
function Toggle(){} // 转换开关状态
};示例
const b = EUDLightBool(); // 默认初始值为 Cleared
DoActions(
b.Set(),
b.Clear(),
b.Toggle(),
);
if ( b.IsSet() ) {
simpleprint("b is set");
}
if ( b.IsCleared() ) {
simpleprint("b is cleared");
}
-
EUDArray
轻静态数组容器,它可以使用
[...]语法初始化声明,不能动态更改尺寸object EUDArray {
function constructor(size : py_int) {}
const length;
};示例
const a = EUDArray(10); // 声明一个尺寸为 10 的数组(下标 0~9)
a[0] = 29; // 将 a 数组中的下标为 0 的元素赋值为 29
println("数组尺寸:{} [0]位置的值:{}", a.length, a[0]); // 数组尺寸:10 [0]位置的值:29
const b = [3, 2, 1]; // 声明一个尺寸为 3 的数组(下标 0~2)并初始化为 b[0] = 3; b[1] = 2; b[2] = 1;
const c = [list(3, 2, 1), 4, list(5, 6)]; // 声明一个尺寸为 6 的数组(下标 0~5)并初始化为 b[0] = 3; b[1] = 2; b[2] = 1; b[3] = 4; b[4] = 5; b[5] = 6;
-
EUDVArray
使用虚拟触发器实现的静态数组容器,它还可以使用
VArray(...)语法初始化声明,不能动态更改尺寸EUDVArray 容器支持静态设定它包含的值的引用类型
它在数组下标为变量时有更快的访问速度
object EUDVArray {
function constructor(size : py_int, basetype : type) : _EUDVArrayClass {}
};
object _EUDVArray {
function constructor(vars : list) {}
const length;
}示例
const a = EUDVArray(4)(list(1, 2, 3, 4)); // 声明一个尺寸为 4 的数组并初始化为 a[0] = 1; a[1] = 2; a[2] = 3; a[3] = 4;
const b = VArray(1, 2, 3, 4); // 和上面那个一样
const c = VArray(list(1, 2, 3, 4)); // 和上面那个一样
const d = VArray(list(1, 2), list(3, 4)); // 和上面那个一样
const d = EUDVArray(4)(); // 声明一个尺寸为 4 的数组,等同 VArray(0, 0, 0, 0);
foreach (i : py_range(4)) {
d[i] = i + 1;
}
// 声明一个尺寸为 4 x 2 的二维数组
const e = EUDVArray(4, EUDVArray(2))(list(VArray(5, 6), VArray(7, 8), VArray(9, 10), VArray(11, 12)));
var a = e[2][1]; // euddraft 0.9.9.8 开始支持该语法
println("e[2][1] == {}", a); // e[2][1] == 10
-
PVariable
玩家变量,它实际上是
EUDVArray(8)()的另一种表示方法,就是对每个玩家都存储不一样的值的一个数组,星际最多 8 个玩家object PVariable {
const length;
};示例
// 以下两个用法等价
const pv1 = PVariable();
const pv2 = EUDVArray(8)();
-
EUDVArrayReader
用于遍历 EUDVArray 的类
object EUDVArrayReader {
function seek(varr_ptr, varr_epd, eudv, acts) {}
function read(acts) {}
}
-
EUDDeque
使用虚拟触发器实现的静态双向队列容器,EUDDeque 是运行时迭代器类型
object EUDDeque {
function constructor(size : py_int, basetype : type) : _EUDDequeClass {}
};
object _EUDDeque {
function constructor() {}
function append(arg) {}
function appendleft(arg) {}
function pop() {}
function popleft() {}
function clear() {}
function empty() {}
const length;
};示例
const dq = EUDDeque(10)();
// `.length` : 获取当前双向队列长度
println("双向队列中元素个数 {}", dq.length);
// `.append(x)` : 将 x 添加到双向队列的最右侧
dq.append(10);
// `.pop()` : 将双向队列最右侧的元素弹出来(移除并返回),你需要先判断双向队列中是否还有元素,如果里面没有元素,直接使用这个方法的行为是未定义的
println("双向队列最右边的的值弹出 {}", dq.pop());
// `.appendleft(x)` : 将 x 添加到双向队列的最左侧
dq.appendleft(13);
// `.popleft()` : 将双向队列最左侧的元素弹出来(移除并返回),你需要先判断双向队列中是否还有元素,如果里面没有元素,直接使用这个方法的行为是未定义的
println("双向队列最左边的的值弹出 {}", dq.popleft());
// `.clear()` : 清空双向队列
dq.clear();
// `.empty()` : 判断当前双向队列中元素个数是否为 0
if (dq.empty()) {
println("双向队列为空");
}
-
StringBuffer
内存静态字符串缓冲操作类型
object StringBuffer {
function constructor(content : py_str | py_bytes) {}
function constructor(len : py_int) {}
function append(*args) {}
function appendf(format_string, *args) {}
function insert(index, *args) {}
function insertf(index, format_string, *args) {}
function delete(start, length=1) {}
function Display() {}
function DisplayAt(line) {}
function print(*args) {}
function printf(format_string, *args) {}
function printfAt(line, format_string, *args) {}
function Play() {}
function fadeIn(*args, line=-1, color=None, wait=1, reset=True, tag=None) {}
function fadeOut(*args, line=-1, color=None, wait=1, reset=True, tag=None) {}
function fadeInf(format_string, *args, line=-1, color=None, wait=1, reset=True, tag=None) {}
function fadeOutf(format_string, *args, line=-1, color=None, wait=1, reset=True, tag=None) {}
function length();
const StringIndex;
const epd;
};除初始化方法外,StringBuffer 对象所有的方法都是非同步方法,都只在
当前玩家 == 本机玩家的机器上生效const buf = StringBuffer(64); // 初始化缓冲区尺寸
setcurpl(P1); // 设置 当前玩家 为 P1
buf.insert(0, "给 玩家1 显示的信息"); // 这一行仅仅会修改 P1 机器上的 buf,因为当前玩家是 P1
if (getuserplayerid() == $P2) { // 本机玩家是 P2 才会执行
buf.insert(0, "这行代码没有卵用"); // 本机玩家是 P2 但当前玩家是 P1 所以这行代码不生效
}
setcurpl(P2); // 设置 当前玩家 为 P2
buf.insert(0, "给 玩家2 显示的信息"); // 这一行仅仅会修改 P2 机器上的 buf,因为当前玩家是 P2
setcurpl(P1);
buf.Display(); // 给 玩家1 显示 “给 玩家1 显示的信息”
setcurpl(P2);
buf.Display(); // 给 玩家2 显示 “给 玩家2 显示的信息” -
StringBuffer
StringBuffer(content)
若 [content] 是字符串或者字节串,则以该字符串或字节串初始化一个 StringBuffer 对象
若 [content] 是一个整数,则以 [content] 作为尺寸尺寸初始化一个 StringBuffer 对象
[content] 是可选参数,默认为整数 218
const s1 = StringBuffer(); // 尺寸为 218 的 StringBuffer 对象,初始内容为 218 个回车符
const s2 = StringBuffer(64); // 尺寸为 64 的 StringBuffer 对象,初始内容为 64 个回车符
const s3 = StringBuffer("havonz"); // 尺寸为 6 的 StringBuffer 对象,初始内容为 “havonz” -
.insert
-
.insert(index, *args)
将可变参数 [*args] 转换成字符串按顺序插入到当前玩家机器上的 StringBuffer 对象缓冲区的[index] * 4位置(索引不是 4 的倍数就不能用这个了) -
.insertf(index, format_string, *args)
将可变参数 [*args] 使用格式 [format_string] 格式化后插入到当前玩家机器上的 StringBuffer 对象缓冲区的[index] * 4位置(索引不是 4 的倍数就不能用这个了)
const s1 = StringBuffer();
s1.insert(0, "havonz");
s1.insert(1, "0");
s1.Display(); // havo0 -
-
.append
-
.append(*args)
将可变参数 [*args] 转换成字符串按顺序插入到当前玩家机器上的 StringBuffer 对象缓冲区中的字符串的末尾 -
.appendf(format_string, *args)
将可变参数 [*args] 使用格式 [format_string] 格式化后插入到当前玩家机器上的 StringBuffer 对象缓冲区中的字符串的末尾
const s1 = StringBuffer();
setcurpl(getuserplayerid());
s1.insert(0);
s1.append("你好!");
s1.appendf("{}{}", PColor(getuserplayerid()), PName(getuserplayerid()) );
s1.Display(); -
-
.delete
.delete(start, length=1)
从当前玩家机器上的 StringBuffer 对象的[start] * 4索引位置删除掉[length] * 4个字节(索引不是 4 的倍数就不能用这个了)
-
.Display
.Display()
将 StringBuffer 缓冲区的字符串打印到当前玩家屏幕滚动信息的最底下哪一行.DisplayAt(line)
将 StringBuffer 缓冲区的字符串打印到当前玩家屏幕滚动信息从上到下第 [line] 行
const s1 = StringBuffer();
setcurpl(getuserplayerid());
s1.insert(0, "你好!星际争霸");
s1.DisplayAt(0); // 输出到最上一行
s1.Display(); // 输出到最下一行 -
.print
-
.print(*args)
使用当前 StringBuffer 将多个参数 [*args] 按顺序打印到当前玩家屏幕滚动信息的下一行,并把最底下的信息往上滚动 -
.printf(formatstring, *args)
使用当前 StringBuffer 以格式 [format_string] 格式化打印多个参数 [*args] 到当前玩家屏幕滚动信息的下一行,并把最底下的信息往上滚动 -
.printfAt(line, formatstring, *args)
使用当前 StringBuffer 以格式 [format_string] 格式化打印多个参数 [*args] 到当前玩家屏幕滚动信息的从上往下的第 [line] 行(取值范围 0~10)
const s1 = StringBuffer();
setcurpl(getuserplayerid());
s1.print("你好!星际争霸"); // 在最底下滚出一条信息
s1.printf("你好!{}{}", PColor(getuserplayerid()), PName(getuserplayerid()) ); // 将上一条信息往上滚动,并将这条消息滚出来
s1.printfAt(0, "你好!{}{}", PColor(getuserplayerid()), PName(getuserplayerid()) ); // 将这条信息从最上一行打印出来 -
-
.Play
.Play()
将当前玩家机器上的 StringBuffer 对象的内容作为声音文件名,播放该声音文件
当目标声音文件包含本地化声音时,则使用 StringBuffer 动态拼接的文件名会无法播放
setcurpl(P1);
buf.insert(0, "sound\\Zerg\\Devourer\\");
buf.append("ZDvPss00.WAV\0");
buf.Display(); // 在 玩家1 的屏幕上的下一行输出 “sound\Zerg\Devourer\ZDvPss00.WAV”
buf.DisplayAt(9); // 在 玩家1 的屏幕上的第十行输出 “sound\Zerg\Devourer\ZDvPss00.WAV”
buf.Play(); // 找到文字指向的 wav 并在 玩家1 的电脑上播放它
StringBuffer("sound\\terran\\advisor\\tadupd04.wav").Play(); // nuclear launch detected. -
.fade
-
.fadeIn(*args, line=0, color=None, wait=1, reset=true, tag=None)
使 [*args] 组合成一个文本从 [line] 行以 [clolor] 颜色渐显出现,步间隔帧数为 [wait],是否重置 [reset],特效文本标签为 [tag],循环调用,返回非 0 表示特效尚未完成还需继续调用,返回 0 表示特效已完成 -
.fadeOut(*args, line=0, color=None, wait=1, reset=true, tag=None)
使 [*args] 组合成一个文本从 [line] 行以 [clolor] 颜色渐隐消失,步间隔帧数为 [wait],是否重置 [reset],特效文本标签为 [tag],循环调用,返回非 0 表示特效尚未完成还需继续调用,返回 0 表示特效已完成 -
.fadeInf(format_string, *args, line=0, color=None, wait=1, reset=true, tag=None)
使 [*args] 使用 [format_string] 格式化成一个文本从 [line] 行以 [clolor] 颜色渐显出现,步间隔帧数为 [wait],是否重置 [reset],特效文本标签为 [tag],返回非 0 表示特效尚未完成还需继续调用,返回 0 表示特效已完成 -
.fadeOutf(format_string, *args, line=0, color=None, wait=1, reset=true, tag=None)
使 [*args] 使用 [format_string] 格式化成一个文本从 [line] 行以 [clolor] 颜色渐隐消失,步间隔帧数为 [wait],是否重置 [reset],特效文本标签为 [tag],返回非 0 表示特效尚未完成还需继续调用,返回 0 表示特效已完成
function 单次渐显然后渐隐文字() {
const buf = StringBuffer(128);
const onceWait = EUDLightVariable(0);
if (getcurpl() != getuserplayerid()) {
return;
}
if (onceWait >= 10000) {
return;
}
const text = py_str("\x13\x04失去\x19人\x04性\n\x13\x04失去\x19很多\x04\n\x13\x04失去\x19兽\x04性\n\x13\x04失去\x19一切\x04");
const tecolor = 4, 2, 0x1E, 5, 0;
if (onceWait <= 0) {
if ( 0 != buf.fadeIn(text, line = 3, color = tecolor, wait = 2, tag = py_str("渐显特效")) ) {
return;
}
}
if (onceWait <= 100) {
DoActions(onceWait.AddNumber(1));
return;
}
TextFX_SetTimer("渐显特效", SetTo, 0);
TextFX_Remove("渐显特效");
if ( 0 != buf.fadeOut(text, line = 3, color = tecolor, wait = 2, tag = py_str("渐隐特效")) ) {
return;
}
TextFX_SetTimer("渐隐特效", SetTo, 0);
TextFX_Remove("渐隐特效");
DoActions(onceWait.SetNumber(10000)); /* 执行完了 */
}
function beforeTriggerExec() {
const cp = getcurpl();
setcurpl(getuserplayerid());
单次渐显然后渐隐文字();
setcurpl(cp);
} -
-
Db
静态内存字节数据类型
object Db {
function constructor(content) {}
function GetDataSize() {}
};支持使用整数、字符串、字节串初始化一段内存字节数据
使用
Db("string")等同于Db(b"string\0")(UTF-8)const buf1 = Db(b"string\0"); // Db(b"string\0")
const buf2 = Db("string"); // Db(b"string\0")
const buf3 = Db(5); // Db(b"\0\0\0\0\0")
-
EUDByteStream
内存字节流操作类
object EUDByteStream {
function seekepd(epd) {}
function seekoffset(ptr) {}
function copyto(stream : EUDByteStream) {}
function readbyte() {}
function writebyte(byte) {}
}const buf = Db(b"\0uck fu\0k fuck");
sprintf(buf, "908 + 8 = {}", 908 + 8);
StringBuffer().printAt(6, ptr2s(buf));
const stream = EUDByteStream();
stream.seekoffset(buf);
StringBuffer().printAt(7, stream.readbyte());
stream.seekoffset(buf);
stream.writebyte(97);
stream.writebyte(98);
stream.writebyte(99);
StringBuffer().printAt(8, ptr2s(buf));
-
CPString已废弃 CPTrick 优化的字符串缓冲操作类
object CPString {
function constructor(content) {}
function Display() {}
function GetVTable() {}
};const s1 = CPString("一个字符串");
const s2 = CPString(b"stringstringstring");
const s3 = CPString(64);
-
DBString已废弃 静态内存字符串
object DBString {
function constructor(content) {}
function GetStringMemoryAddr() {}
function Display() {}
function Play() {}
};const s = DBString("一个很长的字符串\0一个很长的字符串");
const buf = s.GetStringMemoryAddr();
s.Display();
sprintf(buf, "908 + 8 = {}", 908 + 8);
s.Display();