@sogouwap
2017-06-04T17:12:07.000000Z
字数 10534
阅读 7621
前言
本教程由小灰编写,这是
进阶难度的教程
建议在对普通难度学习之后再阅读
我们的QQ群:139659650
点击上述列表中
未打钩旁边的切换按钮,以切换学习等级。
这个教程学习下来需要多少时间?
你需要花一些时间直到你掌握它,并且每天都要坚持编写代码。
根据理解力的不同,需要的时间也不一样(三个月,六个月,或一个星期)
我需要准备什么样的系统?
你需要 Windows 7/8/10 或者 Windows XP 系统。
在 FakeMeta 模块中有一种代码叫 Pev
pev是一个神奇的功能,他几乎可以篡改游戏中的任何数据,比如 生命值,重力,固体类型,移动类型,摩擦力,坐标位置 等等…
我们可以通过 `Pev` 来获取或者更改游戏中的数据
例如:
生命值是 pev_health重力是 pev_gravity坐标系是 pev_origin移动向量 pev_velocity
让我们来看看如何用 Pev 更改以及获取
#include <amxmodx>#include <fakemeta>public test(id){set_pev(id, pev_health, 140.0)}
#include <amxmodx>#include <fakemeta>public test(id){new Float:org[3]pev(id, pev_origin, org)client_print(id, print_chat, "玩家坐标是: [X: %.2f], [Y: %.2f], [%.2f]", org[0], org[1], org[2])}
400.0 的速度向上飞起)
#include <amxmodx>#include <fakemeta>public test(id){new Float:vel[3]vel[2] = 400.0set_pev(id, pev_velocity, vec)}
不难看出,获取也就是只写 `pev` ,而修改则需要写上 `set_pev` 。这就是他们的区别
那
pev类型到底有哪些呢?(下面的代码摘于:百度贴吧)
2.1.1 字符串型实体属性 里面装载另一个字符串pev_string_start = 0, //无效的实体属性 主要用于遍历pev_classname, 实体类型名称 做地图的人会知道这些 实体的类决定了实体是什么用途pev_globalname,pev_model, 实体模型pev_target, 实体的目标 用于控制pev_targetname, 实体的目标 用于控制pev_netname, 实体的网络名称 如玩家游戏名称pev_message, 实体的激发的文字pev_noise, 保留备用的 可以自由存放pev_noise1, 保留备用的 可以自由存放pev_noise2, 保留备用的 可以自由存放pev_noise3, 保留备用的 可以自由存放pev_string_end, //无效的实体属性 主要用于遍历2.1.2 实体值型实体属性 里面装载另一个实体号pev_edict_start, //无效的实体属性 主要用于遍历pev_chain, //不明pev_dmg_inflictor, //被伤害的人/实体 ,攻击者pev_enemy, //敌人 用于NPCpev_aiment, //帽子等装饰 用于连接2个实体pev_owner, //所有者pev_groundentity, //脚下的实体pev_euser1, //保留备用的 可以自由存放pev_euser2, //保留备用的 可以自由存放pev_euser3, //保留备用的 可以自由存放pev_euser4, //保留备用的 可以自由存放pev_edict_end, //无效的实体属性 主要用于遍历2.1.3 小数型(浮点)实体属性 取得或设置实体的详细值pev_float_start, //无效的实体属性 主要用于遍历pev_impacttime, //碰撞时间pev_starttime, //开始时间pev_idealpitch, //理想的PITCH范围pev_ideal_yaw, //理想的YAW范围pev_pitch_speed, //朝向PITCH的速度pev_yaw_speed, //朝向YAW的速度pev_ltime, //时间长度pev_nextthink, //下次心跳时间pev_gravity, //重力pev_friction, //摩擦速度 如滑雪pev_frame, //当前实体播放的动作帧数pev_animtime, //在什么时候开始播放实体动画pev_framerate, //动画播放速度比率pev_scale, //大小 仅用于SPRpev_renderamt, //渲染 详见 fakemeta_util.inc fm_set_renderingpev_health, //生命值pev_frags, //比分pev_takedamage, //实体是否可被伤害 参看HLSDK.INCpev_max_health, //最大生命值pev_teleport_time, //传输时间pev_armortype, //护甲类型pev_armorvalue, //护甲值pev_dmg_take, //伤害值保存pev_dmg_save, //伤害值保存pev_dmg, //实体威力值 用于手雷等爆炸物pev_dmgtime, //实体威力爆发时间 主要用于手雷爆炸物pev_speed, //速度pev_air_finished,pev_pain_finished,pev_radsuit_finished,pev_maxspeed, //最大速度pev_fov, //视野pev_flFallVelocity, //坠落的速度pev_fuser1, //保留备用的 可以自由存放pev_fuser2, //保留备用的 可以自由存放pev_fuser3, //保留备用的 可以自由存放pev_fuser4, //保留备用的 可以自由存放pev_float_end, //无效的实体属性 主要用于遍历2.1.4 整数型实体属性 取得或设置实体的详细值pev_int_start, //无效的实体属性 主要用于遍历pev_fixangle, //朝向与视角朝向同步pev_modelindex, //模型缓存序号pev_viewmodel, //V模型pev_weaponmodel, //P模型pev_movetype, //移动类型 参看HLSDK.INCpev_solid, //固态类型 参看HLSDK.INCpev_skin, //模型的皮肤样式 如果模型有pev_body, //子模型 如果模型有pev_effects, //渲染亮度pev_light_level, //亮度等级pev_sequence, //模型的动作序列pev_gaitsequence, //下半身动作序列 仅用于玩家pev_rendermode, //详见 fakemeta_util.inc fm_set_renderingpev_renderfx, //详见 fakemeta_util.inc fm_set_renderingpev_weapons, //武器表(位)pev_deadflag, //死亡标记 参看HLSDK.INCpev_button, //正在被按下的按键pev_impulse, //手电 喷图 喷射 等pev_spawnflags, //出生标记 参看HLSDK.INCpev_flags, //状态标记 参看HLSDK.INCpev_colormap,pev_team, //队伍pev_waterlevel, //浸泡在水中的程度pev_watertype, //浸泡在哪种液体中pev_playerclass, //玩家角色pev_weaponanim, //武器动作pev_pushmsec, //推时间pev_bInDuck, //蹲下pev_flTimeStepSound, //脚步声pev_flSwimTime, //游泳时间pev_flDuckTime, //蹲下时间pev_iStepLeft, //步伐pev_gamestate, //游戏状态pev_oldbuttons, //之前按下的按键pev_groupinfo, //组类型pev_iuser1, //保留备用的 可以自由存放pev_iuser2, //保留备用的 可以自由存放pev_iuser3, //保留备用的 可以自由存放pev_iuser4, //保留备用的 可以自由存放pev_int_end, //无效的实体属性 主要用于遍历2.1.5 向量实体属性 取得或设置实体的向量(数组)pev_vecarray_start, //无效的实体属性 主要用于遍历pev_origin, //实体坐标pev_oldorigin, //实体之前的坐标pev_velocity, //实体速率pev_basevelocity, //实体基础速率 用于传送带等pev_clbasevelocity,pev_movedir, //可能是移动目标pev_angles, //实体朝向pev_avelocity, //实体受速率影响时朝向变化 仅对实体有效pev_v_angle, //实体视角朝向pev_endpos, //开始点pev_startpos, //结束点pev_absmin, //实体范围 开始pev_absmax, //实体范围 结束pev_mins, //实体大小 开始pev_maxs, //实体大小 结束pev_size, //实体大小pev_rendercolor, //详见 fakemeta_util.inc fm_set_renderingpev_view_ofs, //瞄准视角的速率pev_vuser1, //保留备用的 可以自由存放pev_vuser2, //保留备用的 可以自由存放pev_vuser3, //保留备用的 可以自由存放pev_vuser4, //保留备用的 可以自由存放pev_punchangle, //晃动朝向 仅对玩家有效pev_vecarray_end, //无效的实体属性 主要用于遍历
可能不是所有的
pev类都包含在里面。标准大全可参考fakemeta_const.inc
我们可以 勾住(Hook)一些事件,这些事件在游戏中触发的时候,会调用我们勾住的函数,接下来我们可以从篡改或者打断一些效果。
我们可以勾住这些事件:
复活, 死亡,切换武器,造成伤害,思考,碰撞,重新复活 等等…
更多勾住方式可以参考
ham_const.inc
注册Ham事件的方法: RegisterHam( Ham事件, "勾住什么实体", "调用哪个函数名" , Pre / Post )
RegisterHam 有四个参数供我们填写,每个参数需要用 , 逗号 来逐个隔开,下面我们来看看实例:
public plugin_init(){RegisterHam(Ham_Spawn, "player", "PlayerSpawn", 0)}
我们逐个来解析:
参数1 :
Ham_Spawn
参数2 :"player"
参数3 :"PlayerSpawn"
参数4 :0
这些对应什么呢?
1) 参数1 代表注册 复活 事件,代码为 Ham_Spawn。(更多Ham事件可参考 ham_const.inc)
2) 参数2 "player",这个部分是注册需要勾住什么实体,玩家的实体名是 player (需用 "" 包含起来)
3) 参数3 "PlayerSpawn",这个部分其实就我们需要触发什么函数,填写的是 触发的函数名,函数里的代码由我们自己定义 (需用 "" 包含起来)
4) 参数4:这里涉及到 先(Pre) / 后(Post) 部分,其中0代表Pre,1代表Post 。Ham函数大部分都带有先后顺序,比如对于复活来说,Pre即复活前,Post即复活后。
那整个代码应该是怎么样的呢?
#include <amxmodx>#include <hamsandwich>public plugin_init(){RegisterHam(Ham_Spawn, "player", "PlayerSpawn", 1)}public PlayerSpawn(id){}
- 参数4 如果不填写,默认是Pre(即
0)- 有一些Ham事件其中的
index(索引)不止一个- 上例中的复活触发函数应该勾住
复活之后即 Post
如果索引不止一个呢,代码就会变成下面这样
public test(id, mode){}
那这种一般是怎么使用?
这个方法叫多重传导,一般由两种数据组成 ,如下代码:
test(id, 2)public test(id, mode){client_print(id, print_chat, "Mode的值是 %d", mode)}
如上, 触发了 test 函数,其中传递了 参数2(示例中为 数字2),然后 test 函数会通过 client_print 打印 mode 的值出来,也就是会显示:
Mode的值是: 2对于Ham来说有许多事件都拥有 多个参数, 比如 死亡函数 Ham_Killed ,他拥有三个参数,分别是:
> 受伤者(被杀死的人)> 攻击者(凶手)> 尸体碎片
如果要用函数表达出来就是这样:
public PlayerKilled(victim, attacker){}
小提示:
参数3可以不填,默认就是0
配合Ham注册之后,整个代码就是这样:
#include <amxmodx>#include <hamsandwich>public plugin_init(){RegisterHam(Ham_Killed, "player", "PlayerKilled", 1)}public PlayerKilled(victim, attacker){}
提示:victim 和 attacker 可以按你自己的意图写上去,并不需要完全
照着抄
我们可以在游戏中获取一些信息然后存储下来,比如
玩家名字或 某些字符串信息
比如我们需要获取玩家名字,这里我们需要用到的是 fakemeta 模块中的 pev_netname
我们来细致讲一下,首先我们需要知道要获取谁。通过当前已知条件可以写出这样的代码:
pev(id, pev_netname)
但这样是没有作用的,因为获取之后没有保存下来。那么我们应该如何保存呢
我们来看个代码例句:(获取玩家名字)
public test(id){new fname[33]pev(id, pev_netname, fname, 32)client_print(id, print_chat, "玩家 %s 引发了函数", fname)}
上面的例子不难看出,获取后保存的地方就是 fname 这个数组里面,当我们使用的时候 只需要写上 fname 即可。
那具体是怎么样获取的?
我们首先要分解一下代码。然后我们逐步来分析;
new fname[33] 创建一个临时变量(变量名是 fname 这是一个带数组的存储器,最大存储33字符)id 指的是索引(index),意思是获取谁的名字,要和函数的 索引(index) 对应pev( ) 通过 fakemeta 的 PEV 来获取一些数据,在括号 () 里填写需要获取什么pev_netname 获取玩家的游戏名字(可以通过 fakemeta_const.inc 以查看更多)fname 当我们获取后,将获取到的数据存储到什么地方(这里填写 数组的变量名 )32 我们定义的 数组最大是 33 的存储空间,所以在最后就必须 少一位 。当我们把所有代码组合一下,就变成如下:
new fname[33]pev(id, pev_netname, fname, 32)
TIP:获取到的名字已经被存储到了
fname变量中,你可以随时来调用他
当然除了获取名字,还有更多的变通方法
写法注意:创建的临时变量名,要和 pev( ) 里面的那个进行对应。
我们来看看还有哪些其他的使用方式
new class[33]pev(id, pev_classname, class, 32)
new jmodel[33]pev(id, pev_model, model, 32)
更多的
pev_可参考fakemeta_const.inc
* 使用的变量存储是临时变量
本次我们要学到的是 给予指定装备,简单说就是给玩家特定的 武器
本次我们要用到一个新的模块INC,他是 fakemeta_util.inc 他会给我们带来很多快捷方便的 stock(自定义函数),在以后我们也会经常用到。
首先定义模块代码
#include <amxmodx>#include <fakemeta_util> //这里是新的INC
我们本次需要用到的是 fakemeta_util 中提供的 fm_give_item 这串代码
他的使用方法很简单 ,比如我们需要给玩家一个 AK47 ,代码即:
fm_give_item(id, "weapon_ak47")
这次和之前的 CSW_ 有点区别,但是区别不大,只是将
CSW_变成了weapon_
现在尝试一下将:之前学到的 获取名字 在配合本次学到的 给予武器 将代码写出来
示例:
#include <amxmodx>#include <fakemeta_util>public plugin_init(){regsiter_clcmd("say /giveak", "giveak_func")}public giveak_func(id){if(!is_user_alive(id)) return //如果玩家死亡 返回new fname[33]pev(id, pev_netname, fname, 32) //获取名字 并存储到 fname变量中client_print(id, print_chat, "玩家 %s 得到了Ak47", fname) //打印信息在屏幕上fm_give_item(id, "weapon_ak47") //给予武器 Ak47}
这样就完成啦
weapon_后面接上的武器名 需要注意一定是小写
死亡的时候不需要让玩家得到武器,所以我们可以添加is_user_alive再配合return来做个判断
坐标位置又叫 坐标系,他决定了目标在地图中的所在 位置
我们可以通过
pev_origin来获取 目标的当前坐标位置
示例:
new Float:origin[3]pev(id, pev_origin, origin)client_print(id, print_chat, "坐标位置: [X: %.0f], [Y: %.0f], [Z: %.0f]", origin[0], origin[1], origin[2])
也许你不太明白?没关系,继续看下面
坐标是由
X,Y,Z三个轴组成的,其中Z轴代表的是 上下高度。
X和Y轴 决定了 左右以及前后的位置
首先,我们用 pev_origin 来获取目标的坐标,然后存储到变量中(注意:因为不是字符串信息,所以不用些后面的 33, 32 什么的)
new Float:org[3]pev(id, pev_origin, org) //获取目标的坐标 存储到 org 数组变量中
这里这个数组变量就存储了坐标,因为坐标是 X,Y,Z 三个轴组成,所以数组中的每个值代表了 如下定义:
org[0] = X轴 (前后或左右)org[1] = Y轴 (前后或左右org[2] = Z轴 (上下)
- 注意:使用的
变量存储是临时变量
如果我们要触发获取坐标的函数,代码应该是这样
#include <amxmodx>#include <fakemeta>public plugin_init(){register_clcmd("say /getorigin", "get_origin")}public get_origin(id){new Float:origin[3]pev(id, pev_origin, origin)client_print(id, print_chat, "我的坐标位置: [X: %.0f], [Y: %.0f], [Z: %.0f]", origin[0], origin[1], origin[2])}
我们可以利用伤害标记 pev_takedamage 来让自己免去受到伤害。通俗的说 我们可以让自己无敌
这个 pev_takedamage有三个返回值
0.0 = DAMAGE_NO //无法受到伤害1.0 = DAMAGE_YES //可以受到伤害2.0 = DAMAGE_AIM //可以受到伤害(至于区别嘛 呃… 不太清楚)。一般只用到上面两个
那我们应该如何写才能无敌?
很简单,像这样
set_pev(id, pev_takedamage, 0.0) //让索引(index) 无法受到伤害无敌
是不是很简单呢?
配合主代码 我们结合起来可以是这样:
#include <amxmodx>#include <fakemeta>public plugin_init(){register_clcmd("say /god", "god_func")}public god_func(id){client_pritn(id, print_chat, "我无敌啦")set_pev(id, pev_takedamage, 0.0)}
注意:
由于Cs自带的判断问题,你无法在下一局依然无敌。若要解决需要用到玩家思考。但是这里暂时不讲。
点到为止。以后我们会学到用开关来写无敌
我们也许在某些服务器见过这样的效果:
[玩家名] 连接服务器。
这是怎么实现的呢?
这里,我们会用到一个叫非注册性的函数
我们知道 注册客户端命令 需要用到 register_clcmd,该代码必须注册后 游戏中才会有应有的效果,但某些代码是不需要注册的,也就是在事件引发的时候自动触发。比如玩家连接游戏就会自动触发一个事件,我们通过那个事件 就可以完成我们想要的效果。
玩家进入服务器触发 client_connect 函数,他不需要我们注册
示例:
#include <amxmodx>public client_connect(id){}
也许你发现了有点太简单了吧 , 是的… 通过这种函数我们甚至不用写 plugin_init 直接就可以写出函数名来触发效果
其中
id代表index索引即:谁连接了服务器
那我们怎么才能写出提示所有玩家某个人进入的效果呢?
这个可以配合我们之前学到的 获取名字 来实现~
示例:
public client_connect(id){new fname[33]pev(id, pev_netname, fname, 32)client_print(0, print_chat, "玩家 %s 连接服务器。", fname)}
你可能注意到了什么不对劲的地方,client_print 的索引怎么写的是 0 ? 不是应该写id吗,嗯 看来你注意到了细节
id代表索引,我们现在也许都知道了,可是如果要发送给所有人的话,写id显然不是我们想要的效果,这就意味着 玩家进入的时候 提示的信息只发给他自己,其他人完全不知道,所以这里写
0代表 给所有人发送信息
注意:因为是 pev 所以我们要加上 fakemeta 模块定义
所以整个代码是这样:
#include <amxmodx>#include <fakemeta>public client_connect(id) //连接服务器触发{new fname[33]pev(id, pev_netname, fname, 32)client_print(0, print_chat, "玩家 %s 连接服务器。", fname)}
注意:若在服务器使用
client_connect触发 ,会导致玩家连接时重复触发两次,若配合client_print会显示这样的结果:
[玩家名] 连接服务器。[玩家名] 连接服务器。
可通过添加变量来解决,此处不详讲。
和 七、判断玩家连接服务器 的方法一样,我们这里只需要将函数名改为 client_disconnect 即可
示例:
#include <amxmodx>#include <fakemeta>public client_disconnect(id) //断开连接时触发{new fname[33]pev(id, pev_netname, fname, 32)client_print(0, print_chat, "玩家 %s 退出服务器。", fname)}
和 七、判断玩家连接服务器 的方法一样,我们这里只需要将函数名改为 client_putinserver 即可
示例:
#include <amxmodx>#include <fakemeta>public client_putinserver(id) //进入服务器的时候触发{new fname[33]pev(id, pev_netname, fname, 32)client_print(0, print_chat, "玩家 %s 进入服务器。", fname)}
client_connect 和 client_putinserver 的区别是什么?
其实很简单,前者是连接服务器的瞬间就会触发,而后者是必须完全进入服务器之后才会触发,
client_putinserver的触发时间段可以理解为玩家进入服务器后选择人物时/或看见MOTD时