amxx插件开发新手教程4-进阶
条评论前言
我们这一章节将会再深入了解amxx插件的开发,通过本篇文章,你将可以掌握pev和ham函数,可以更快捷地修改玩家生命值、判断玩家游戏状态等等。有疑问可以在文章底部留言。
FakeMeta(Pev)
在FakeMeta模块中有一种函数叫pev
pev是一个神奇的功能,他几乎可以篡改游戏中的任何数据,比如生命值,重力,固体类型,移动类型,摩擦力,坐标位置等等……
我们可以通过Pev来获取或者更改游戏中的数据
例如:
- 生命值是 pev_health
- 重力是 pev_gravity
- 坐标系是 pev_origin
- 移动向量 pev_velocity
让我们来看看如何用pev更改以及获取
示例1:将玩家生命值改为140
1 |
|
示例2:获取玩家坐标位置
1 |
|
示例3:设定玩家移动向量
玩家会以400.0的速度向上飞起
1 |
|
不难看出,获取也就是只写
pev,而修改则需要写上set_pev。这就是他们的区别
更多的PEV常量
1 | // 字符串型实体属性 里面装载另一个字符串 |
这里并没有包含所有的
pev都包含在里面。标准大全可参考fakemeta_const.inc
HAM事件钩子
即Hamsandwich,我们可以勾住(Hook)一些事件,这些事件在游戏中触发的时候,会调用我们勾住的函数,接下来我们可以从篡改或者打断一些效果。
我们可以勾住这些事件:复活,死亡,切换武器,造成伤害,思考,碰撞,重新复活等等……
所谓
思考,即think事件,表示服务端接收到客户端主动发送的数据包,如按下前进键、或者按下鼠标左键等
更多勾住方式可以参考ham_const.inc
注册Ham事件的方法:RegisterHam( Ham事件, "勾住什么实体", "调用哪个函数名" , Pre / Post )
RegisterHam有四个参数供我们填写,每个参数需要用,逗号来逐个隔开,下面我们来看看实例:
勾住玩家复活的时候
1 | public plugin_init() |
我们逐个来解析:
- 参数1 : Ham_Spawn
- 参数2 : “player”
- 参数3 : “PlayerSpawn”
- 参数4 : 0
这些对应什么呢?
- 参数1:代表注册
复活事件,代码为 Ham_Spawn。(更多Ham事件可参考 ham_const.inc) - 参数2:
"player",这个部分是注册需要勾住什么实体,玩家的实体名是player(需用""包含起来) - 参数3:
"PlayerSpawn",这个部分其实就我们需要触发什么函数,填写的是触发的函数名,函数里的代码由我们自己定义 (需用""包含起来) - 参数4:这里涉及到
先(Pre)/后(Post)部分,其中0代表Pre,1代表Post。Ham函数大部分都带有先后顺序,比如对于复活来说,Pre即复活前,Post即复活后。
那整个代码应该是怎么样的呢?
1 |
|
需要注意的是:
- 参数4 如果不填写,默认是Pre(即
0) - 有一些Ham事件其中的
index(索引)不止一个 - 上例中的复活触发函数应该勾住
复活之后即Post
多个索引的传递
如果索引不止一个呢,代码就会变成下面这样
1 | public test(id, mode) |
那这种一般是怎么使用的呢?
这个方法叫多重传导,一般由两种数据组成 ,如下代码:
1 | test(id, 2) |
如上,触发了test函数,其中传递了参数2(示例中为数字2),然后test函数会通过client_print打印mode的值出来,也就是会显示:Mode的值是: 2
对于Ham来说有许多事件都拥有多个参数,比如死亡函数Ham_Killed,他拥有三个参数,分别是:
- 受伤者(被杀死的人)
- 攻击者(凶手)
- 尸体碎片
小提示:参数3可以不填,默认就是0
配合Ham注册之后,整个代码就是这样:
1 |
|
提示:victim和attacker可以按你自己的意图写上去,并不需要完全照着抄
获取数据然后存储
我们可以在游戏中获取一些信息然后存储下来,比如玩家名字或某些字符串信息
比如我们需要获取玩家名字,这里我们需要用到的是fakemeta模块中的pev_netname
我们来细致讲一下,首先我们需要知道要获取谁。通过当前已知条件可以写出这样的代码:
1 | pev(id, pev_netname) |
但这样是没有作用的,因为获取之后没有保存下来。那么我们应该如何保存呢
我们来看个代码例句:(获取玩家名字)
1 | public test(id) |
上面的例子不难看出,获取后保存的地方就是fname这个数组里面,当我们使用的时候 只需要写上fname即可。
那具体是怎么样获取的?
我们首先要分解一下代码。然后我们逐步来分析:
new fname[33]创建一个临时变量(变量名是fname这是一个带数组的存储器,最大存储33字符)id指的是索引(index),意思是获取谁的名字,要和函数的索引(index)对应pev()通过fakemeta的 PEV 来获取一些数据,在括号()里填写需要获取什么pev_netname获取玩家的游戏名字(可以通过fakemeta_const.inc以查看更多)fname当我们获取后,将获取到的数据存储到什么地方(这里填写 数组的变量名 )32我们定义的 数组最大是33的存储空间,所以在最后就必须少一位。
当我们把所有代码组合一下,就变成如下:
1 | new fname[33] |
TIP:获取到的名字已经被存储到了fname变量中,你可以随时来调用他
扩展思维
当然除了获取名字,还有更多的变通方法
写法注意:创建的临时变量名,要和pev()里面的那个进行对应。
我们来看看还有哪些其他的使用方式
获取实体名
1 | new class[33] |
获取模型路径
1 | new jmodel[33] |
更多的
pev_可参考fakemeta_const.inc*使用的变量存储是临时变量
给予玩家指定的装备
本次我们要学到的是 给予指定装备,简单说就是给玩家特定的武器
本次我们要用到一个新的模块INC,他是fakemeta_util.inc他会给我们带来很多快捷方便的stock(自定义函数),在以后我们也会经常用到。
首先定义模块代码
1 |
我们本次需要用到的是fakemeta_util中提供的fm_give_item这串代码
他的使用方法很简单 ,比如我们需要给玩家一个AK47,代码即:
1 | fm_give_item(id, "weapon_ak47") |
这次和之前的
CSW_有点区别,但是区别不大,只是将CSW_变成了weapon_
现在尝试一下将:之前学到的获取名字在配合本次学到的给予武器将代码写出来
示例:
1 |
|
此时,当你在客户端控制台输入say /giveak或者按Y键输入/giveak,那么你就会得到一把AK47武器。
注意:
weapon_后面接上的武器名需要注意一定是小写
死亡的时候不需要让玩家得到武器,所以我们可以添加is_user_alive再配合return来做个判断
坐标位置
坐标位置又叫坐标系,他决定了目标在地图中的所在位置
我们可以通过pev_origin来获取目标的当前坐标位置
示例:
1 | new Float:origin[3] |
也许你不太明白?没关系,继续看下面
坐标是由X,Y,Z三个轴组成的,其中Z轴代表的是上下高度。X和Y轴决定了左右以及前后的位置
首先,我们用pev_origin来获取目标的坐标,然后存储到变量中(注意:因为不是字符串信息,所以不用些后面的33,32什么的)
1 | new Float:org[3] |
这里这个数组变量就存储了坐标,因为坐标是X,Y,Z三个轴组成,所以数组中的每个值代表了 如下定义:
1 | org[0] = X轴 (前后或左右) |
注意:使用的变量存储是临时变量
如果我们要触发获取坐标的函数,代码应该是这样
1 |
|
伤害标记
我们可以利用伤害标记pev_takedamage来让自己免去受到伤害。通俗的说我们可以让自己无敌
这个pev_takedamage有三个返回值
1 | 0.0 = DAMAGE_NO //无法受到伤害 |
那我们应该如何写才能无敌?
很简单,像这样
1 | set_pev(id, pev_takedamage, 0.0) //让索引(index) 无法受到伤害无敌 |
是不是很简单呢?
配合主代码 我们结合起来可以是这样:
1 |
|
注意:
由于CS1.6自带的判断问题,你无法在下一局依然无敌。若要解决需要用到玩家思考。但是这里暂时不讲。点到为止。以后我们会学到用开关来写无敌
判断玩家连接服务器
我们也许在某些服务器见过这样的效果:
[玩家名] 连接服务器。
这是怎么实现的呢?
这里,我们会用到一个叫非注册性的函数
什么是非注册性函数?
我们知道 注册客户端命令 需要用到register_clcmd,该代码必须注册后 游戏中才会有应有的效果,但某些代码是不需要注册的,也就是在事件引发的时候自动触发。比如玩家连接游戏就会自动触发一个事件,我们通过那个事件就可以完成我们想要的效果。
如何实现?
玩家进入服务器触发client_connect函数,他不需要我们注册
示例:
1 |
|
也许你发现了有点太简单了吧,是的!!通过这种函数我们甚至不用写plugin_init直接就可以写出函数名来触发效果
其中id代表index索引即:谁连接了服务器
那我们怎么才能写出提示所有玩家某个人进入的效果呢?
这个可以配合我们之前学到的获取名字来实现~
示例:
1 | public client_connect(id) |
你可能注意到了什么不对劲的地方,client_print的索引怎么写的是0? 不是应该写id吗,嗯,看来你注意到了细节
client_print()中第一个索引0是什么意思?
id代表索引,我们现在也许都知道了,可是如果要发送给所有人的话,写id显然不是我们想要的效果,这就意味着玩家进入的时候 提示的信息只发给他自己,其他人完全不知道,所以这里写0代表给所有人发送信息
注意:因为是pev所以我们要加上fakemeta模块定义
所以整个代码是这样:
1 |
|
注意:若在服务器使用client_connect触发,会导致玩家连接时重复触发两次,若配合client_print会显示这样的结果:
1 | [玩家名] 连接服务器。 |
可通过添加变量来解决,此处不详讲。
判断玩家断开连接
和判断玩家连接服务器的方法一样,我们这里只需要将函数名改为client_disconnect即可
示例:
1 |
|
判断玩家进入服务器
和判断玩家连接服务器的方法一样,我们这里只需要将函数名改为client_putinserver即可
示例:
1 |
|
玩家连接和进入服务器的区别
client_connect和client_putinserver的区别是什么?
其实很简单,前者是连接服务器的瞬间就会触发,而后者是必须完全进入服务器之后才会触发,client_putinserver的触发时间段可以理解为玩家进入服务器后选择人物时/或看见MOTD时触发。