11 控制台变量进阶 - eLecCap1taL/CS2-CFG-Wiki GitHub Wiki
在这个章节,我们将了解控制台变量的进阶用法
管道符会是这个章节的重要前置知识,务必确保你学习了管道符章节
cvar 的数值运算是非常重要的,但自定义 cvar 不能使用 incrementvar
和 multvar
,我们需要一个内置的 cvar 来用于计算。它需要:
- 不会影响游戏行为
- 能存储数值,最好能存储小数
- 拥有相当大的数值范围限制
幸运的是,我们找到了三个完美符合这个标准的内置 cvar,他们是:
joy_yaw_sensitivity
joy_pitch_sensitivity
joy_yawsensitivity
这是用于控制手柄视角灵敏度的 cvar,不会对键鼠游戏有影响,支持小数,同时数值范围相当大。我们在后面会经常使用它们。
我们先来梳理一下获取 cvar 值有哪些方法。🤔
适用于所有 cvar 🤗
直接把 cvar 名当做指令,值会以 cvar名字 = 值
的形式输出。此输出可以用管道符捕获
适用于内置 cvar,且要获取的值必须是整数或小数 🥵
运行 incrementvar cvar名字 -99999999999 99999999999 0
,值会以 cvar名字 值
的形式输出。此输出可以用管道符捕获
想要做计算,赋值操作是必不可少的
赋值并不简单,你可能会直接尝试 cvar1 cvar2
,但这样并不能赋值,而是把 cvar1
的内容直接改成了 "cvar2"
假设我们要把 A cvar(A可以是任意 cvar,内置自定义均可)赋值给 B cvar。下面来讨论一下赋值应该如何操作
所有的自定义 cvar 都可以存储任意类型,同时也包括一部分内置的 cvar
如果我们在控制台直接输入 A
,它的值将会以 A = 值
的格式被输出,可以用管道符捕获这种输出
我们把这个输出通过管道符传递给 toggle B
,并事先把 B
赋值为 =
,就完成了 cvar 的赋值
完整代码:
setinfo A 123 //A 可以是任意cvar,此处自定义一个,内置的也可以
setinfo B 0 //B 是要被赋值的 cvar,此处自定义一个。
A
//输出 A = 123
B =
//把 B 赋值为 =
A | toggle B
//通过管道符传递,此指令相当于 toggle B A = 123,又因为 B 原先的值是 =,它被赋值成了 123
因为所有的自定义 cvar 都可以存储任意类型,因此 B 一定是内置 cvar
这个方法稍微麻烦一些,但非常重要 😥
例如 joy_yaw_sensitivity
就只能存储数值,因此刚才的方法失效了,因为不能预赋值 joy_yaw_sensitivity
为 =
💀👆
这里说一个技巧,
incrementvar
和multvar
都接受三个参数,前两个分别为 最小值 和 最大值。它们理论上也必须是数值。但事实上,如果我们提供一个文本作为参数,指令依然能执行,他会把所有文本输入当成0
处理。这个技巧将会在后面多次用到。😉
我们先自定义一个 cvar,名字为 -9999999999
这种很小的数字,并把 A 的值用刚才的方法赋值过去
setinfo A 123 //A 可以是任意cvar,此处自定义一个,内置的也可以
//定义临时 cvar
setinfo -9999999999 0
//把 A 赋值给 -9999999999
-9999999999 =
A | toggle -9999999999
-9999999999
//输出 -9999999999 = 123
//赋值成功
然后我们把 B 赋值为 -1
,并使用 multvar,最后再乘以 -1
应该有些抽象,看代码:
-9999999999
//输出 -9999999999 = 123
//这是刚才的赋值
B -1
//把 B 赋值为 -1
-9999999999 | multvar B
//管道符传递后相当于 multvar B -9999999999 = 123
//又因为 CS2 会把非数值输入当成 0,所以最后变成 multvar B -9999999999 0 123
//可以自己想一想
B
//输出 B = -123
multvar B 0 9999999999 -1
//把 B 乘以 -1 变回正值
B
//输出B = 123
完整代码:
setinfo A 123
//B 是一个内置 cvar,只支持存储数值
setinfo -9999999999 =
A | toggle -9999999999
B -1
-9999999999 | multvar B
multvar B 0 9999999999 -1
和刚才基本类似,可以类比理解 🤔
setinfo A -123
//B 是一个内置 cvar,只支持存储数值
setinfo -9999999999 =
A | toggle -9999999999
B 0
-9999999999 | incrementvar B
有时候,我们会需要备份一个 cvar,下面来讲解两种常用方法
直接创建一个自定义 cvar,把要备份的 cvar 赋值过去,需要复原的时候复制回来即可 🤗
如果要备份的 cvar 是内置 cvar,且支持数值操作。我们可以用 alias 存储。
例如,我们要备份玩家的帧数上限(fps_max
),这可以由如下代码完成:
incrementvar fps_max -9999999 9999999 0 | alias recov_fpsmax
管道符左侧的输出是 fps_max 帧率限制值
传递给右侧,被定义为了 recov_fpsmax
相当于 alias recov_fpsmax fps_max 帧率限制值
这样,在我们修改过 fps_max
之后,执行 recov_fpsmax
就可以把 fps_max
还原了 😋
这个例子的另一个重要目的是:说明 cvar 与 实际指令 之间存在关系。我们很快就会需要这种思想 🤔
在这一部分中,我们会默认操作的 cvar 都是可用于计算的内置 cvar。因为自定义 cvar 都可以用刚才的方法赋值给内置 cvar
同时,我们默认运算的值域不会过大,对于小数类型,不能超过 999999984306749440.000000,但示例代码中的极大极小值均不严格,都是类似 99999
这种随便敲的数字。你可以根据需求自行修改 🙂
下面的讲解部分会比较少,但是代码会有注释,可以自行多次阅读理解,或在代码中间输出 cvar 的值辅助理解 🤒
以下全部以最大值为例,如果要取最小值,乘 -1 之后取最大值即可
什么是取最值?
举个例子:123 与 50 取最大值,结果是 50
简单的
multvar A -99999999999999999 要取的最大值 1
A 1234
B 100
//假设 A 要对 B 取最大值
//值域平移
incrementvar A -999999999999999 9999999999999999 10000000000
incrementvar B -999999999999999 9999999999999999 10000000000
//取极值
incrementvar A -999999999999 9999999999999 0 | echo 1 | multvar A
//值域平移
incrementvar A -999999999999999 9999999999999999 -10000000000
incrementvar B -999999999999999 9999999999999999 -10000000000
这里很有意思,我们用到了 key_findbinding
//假设我们要判断 A 是否为 114514.000000
setinfo B =
A | toggle B
toggle B fail 114514.000000 succ
//利用 toggle
//如果 B 为 114514.000000,B 会变成 succ
//否则,B 会变成 fail
B | bind JOY30
//把 B 的内容绑定给无用的手柄按键 JOY30
//例如相当于 bind JOY30 B = succ
//这显然并不是个指令,但我们并不触发它,继续往下看
alias [Player
alias 0] say 通过
key_findbinding succ | alias
[Player
最后这一段是如何检测的?
key_findbinding 文本:用于检测有哪些按键绑定了包含给定文本的内容
例如,如果你的 w 绑定了 +forward,它会输出:[Player 0] : "w" = "+forward"
我们利用这一点,搜索 succ
文本,只有当绑定为 bind JOY30 B = succ
时才会输出内容,当绑定为 bind JOY30 B = fail
时则什么也不输出
输出的第一部分是 [Player 0]
,这中间有个空格,我们把它传递给 alias
,定义了一个名为 [Player
的 alias,内容为 [Player
。
因此我们只需要提前定义 [Player
为空,执行检测后,如果检测成功,[Player
的内容就是 0]
,否则为空。再运行 [Player
,如果 0]
被运行说明检测通过
与刚才类似
//假设我们要判断 A 是否等于 B
setinfo C =
A | toggle C
B | echo succ | toggle C fail
//利用 toggle
//相当于 toggle C fail B = B的值 succ
C | bind JOY30
alias [Player
alias 0] say 通过
key_findbinding succ | alias
[Player
对另一个 cvar 取最大值,再判断相等
先判断相等,再对另一个 cvar 取最大值,再判断相等
与大于(等于)类似
简单的
incrementvar A -999999999 9999999999 要加的数值
A 123
B 100
//假设我们要把 A 加到 B 上
//赋值给临时量
setinfo -2000000000 =
A | toggle -2000000000
//值域平移
incrementvar B -2000000000 2000000000 -1000000000
//以 -1000000000 为值域原点计算
//此处相当于 incrementvar B -2000000000 0 123
-2000000000 | incrementvar B
//值域平移
incrementvar B -2000000000 2000000000 1000000000
需要值域平移的核心原因是:我们需要值域全部在负数部分
这是因为 cvar名
=
在被当做 最小值 和 最大值 参数时,cvar名
是极小值(例如这个例子里的 -2000000000),=
会被当成 0,因此值域是 [-2000000000,0]
和加法一样做
简单的
multvar A -9999999999 99999999999 要乘的数值
情况会变的有些复杂 😪
首先根据上面的说明,我们必须保证结果的值域全部在负数部分
因此我们需要先假定一个数字绝对值大小的上限
我们下面的操作需要保证
问:如果我要算的值的大小超过了
$V$ 怎么办?答:自行调整
$V$ 。但你应该确保你的最终答案不会超过 999999984306749440.000000
我们要计算
这样有什么好处?我们可以保证
下面给出一个示例代码,自定义两个 cvar,演示它们相乘的过程。(利用 joy_sensitivity
)😋
之前讲过的内容将不再给出具体代码
setinfo A 1234
setinfo B 3421
//假设 V 为 100000000
//计算 -A*100000000 并存进临时自定义 cvar mul1
//需要的操作:赋值与 cvar * 固定值
//此处省略具体代码
//计算 A*100000000 并存进临时自定义 cvar mul2
//需要的操作:赋值与 cvar * 固定值
//此处省略具体代码
//计算 100000000*100000000 并存进临时自定义 cvar mul3,赋值
//需要的操作:赋值
//此处省略具体代码
//下面是真正的 cvar * cvar
//把 A 赋值给 joy_yaw_sensitivity,此处省略具体代码,直接赋值
joy_yaw_sensitivity 1234
//值域平移
incrementvar joy_yaw_sensitivity -99999999999999999999 99999999999999999999 -100000000
//把 B 赋值给 joy_pitch_sensitivity,此处省略具体代码,直接赋值
joy_pitch_sensitivity 3421
//值域平移
incrementvar joy_pitch_sensitivity -99999999999999999999 99999999999999999999 100000000
//创建临时 cvar 并赋值
setinfo -99999999999999999999 =
joy_yaw_sensitivity | toggle -99999999999999999999
//乘法
-99999999999999999999 | multvar joy_pitch_sensitivity
//现在 joy_pitch_sensitivity 里存储的是 (A-V)(B+V)
//下面是一些加法
//把 mul1 转移进 joy_yaw_sensitivity 并加给 joy_pitch_sensitivity
//需要的操作:赋值与 cvar + cvar
//此处省略具体代码
//把 mul2 转移进 joy_yaw_sensitivity 并加给 joy_pitch_sensitivity
//需要的操作:赋值与 cvar + cvar
//此处省略具体代码
//把 mul3 转移进 joy_yaw_sensitivity 并加给 joy_pitch_sensitivity
//需要的操作:赋值与 cvar + cvar
//此处省略具体代码
joy_pitch_sensitivity
//这就是最后的结果了 😀
提前计算固定值的倒数,转化为 cvar * 固定值
很遗憾,目前并没有直接计算的好方法。不过我们可以想想我们已经有了什么操作:🤔
- 完全的加减乘运算
- 判断相等
- 判断是否大于(等于)
- 判断是否小于(等于)
这已经完全允许我们使用 二分法 在
一段 C++ 代码实现,由 GPT 生成,可以用 cfg 实现相同的逻辑:
double divide(double a, double b) {
const double epsilon = 1e-6;
// 检查分母是否为零
if (b == 0) {
throw "Division by zero";
}
// 判断结果的符号
bool is_negative = false;
if (a < 0 && b > 0) {
is_negative = true;
} else if (a > 0 && b < 0) {
is_negative = true;
} else {
is_negative = false;
}
// 取绝对值
double abs_a = a;
if (a < 0) {
abs_a = -a;
}
double abs_b = b;
if (b < 0) {
abs_b = -b;
}
// 二分查找的范围
double low = 0;
double high;
if (abs_a >= abs_b) {
high = abs_a;
} else {
high = 1; // 当 |a| < |b| 时,商的范围是 [0, 1]
}
double result = 0;
// 二分查找
while (high - low > epsilon) {
double mid = (low + high) / 2;
if (mid * abs_b < abs_a) {
low = mid; // 商太小,增加 lower bound
} else {
high = mid; // 商太大,减小 upper bound
}
result = mid;
}
// 根据符号调整结果
if (is_negative) {
result = -result;
}
return result;
}
😋😋😋😋