Hydralisk 发表于 2005-7-15 10:51:22

【教程】关于message(重要课程!)

教程(一)深入研究message
在AMX AMXX的娱乐插件里,您是否曾经被光环,爆炸,闪电,激光,烟雾,火焰等等的效果震撼呢?您试否曾经见过您的屏幕突然变白,突然变黑,突然开始振颤,甚至您看到屏幕右上角一个活人把一个死人杀死若干次的标志呢?这些,全都离不开message(消息),
消息如此的有用处,大家可能还不太理解,简单的message_begin, message_end, write_byte, write_coord 等等命令如何实现这样的功能。下面我就来教大家,自认为message是AMX AMXX脚本编写最有用处的命令之一。
支持AMX AMXX

技术难度系数:★★★☆
理解难度系数:★★★★☆

深入研究message,我将这分成两部分。
第一部分,message对效果的操作和第二部分,message对事件的操作。

第一部分,message对效果的操作。学习这部分,您需要有一定英文基础,至少您应该会查英汉词典。在附件的const.h里用得着。
所谓对效果的操作,就是用message创建诸如爆炸,闪电等等效果。首先,我们先熟悉一下用message创建效果的通用格式
①        创建所有人都能看见的效果
message_begin(MSG_BROADCAST, SVC_TEMPENTITY)
write_byte(效果索引号码)
write_***
………
message_end()

②        创建只有一个人能看见的效果
message_begin(MSG_ONE, SVC_TEMPENTITY,{0,0,0},玩家id)
write_byte(效果索引号码)
write_***
………
message_end()

通用格式就是这么两个,玩家id就是玩家索引号码,效果索引号码存在于附件const.h中。下面,我来举几个例子。
实战(一)创建爆炸效果。
我们打开const.h,稍向下翻,实体索引号码通常都是
#define TE_效果名称 效果索引号码
并且,紧挨着他的下面通常有几行注释,以爆炸效果为例:(这个出自const.h)
#define        TE_EXPLOSION                3                // additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps
// coord coord coord (position)
// short (sprite index)
// byte (scale in 0.1's)
// byte (framerate)
// byte (flags)
//
// The Explosion effect has some flags to control performance/aesthetic features:
#define TE_EXPLFLAG_NONE                0        // all flags clear makes default Half-Life explosion
#define TE_EXPLFLAG_NOADDITIVE        1        // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite)
#define TE_EXPLFLAG_NODLIGHTS        2        // do not render dynamic lights
#define TE_EXPLFLAG_NOSOUND                4        // do not play client explosion sound
#define TE_EXPLFLAG_NOPARTICLES        8        // do not draw particles

其中出现#define        TE_EXPLOSION                3,就是我说刚才说的形式,EXPLOSION(爆炸)是效果名,3是效果索引。但注意,下边还有什么 #define TE_EXPLFLAG_**** 数字 一些东西,这些就不是实体索引,因为紧挨着他们下边没有注释。
#define TE_EXPLOSION 3 下面的注释是非常有用的。我们来看看。
// coord coord coord (position)
// short (sprite index)
// byte (scale in 0.1's)
// byte (framerate)
// byte (flags)

这些注释告诉您,write_byte(效果索引) 下边该写什么,例如这里,//coord coord coord (position) 告诉您,write_byte(效果索引)下边应该写3个write_coord 表示创造爆炸效果的位置。//short (sprite index) 表示再写一个write_short表示spr索引,//byte (scale in 0.1's): 下边再写一个write_byte表示spr显示大小,按0.1倍计算,//byte (framerate) 下边再写一个write_byte表示每秒钟贞数,// byte(flages) 下边再写一个write_byte 表示标识。注意,这些的顺序是绝对不能颠倒的!然后,他就在下边给您解释标识如何使用:
// The Explosion effect has some flags to control performance/aesthetic features:
#define TE_EXPLFLAG_NONE                0        // all flags clear makes default Half-Life explosion
#define TE_EXPLFLAG_NOADDITIVE        1        // sprite will be drawn opaque (ensure that the sprite you send is a non-additive sprite)
#define TE_EXPLFLAG_NODLIGHTS        2        // do not render dynamic lights
#define TE_EXPLFLAG_NOSOUND                4        // do not play client explosion sound
#define TE_EXPLFLAG_NOPARTICLES        8        // do not draw particles
这个就得您自己翻译了,所以我说,需要一定英文基础的。于是我们知道,创建正常的爆炸,标识为0就可以了。
于是,按照const.h里所给的格式,我们就可以写出以下内容:
message_begin(MSG_BROADCAST,SVC_TEMPENTITY)
write_byte(3)
write_coord()
write_coord()
write_coord()
write_short()
write_byte()
write_byte()
write_byte()
message_end()


当然,仅仅这样是不能创建效果的。因为,每个write_byte write_coord write_****(其他) 的后面必须含有一个值,下面,我先把spr索引讲一下。想获得spr索引,您必须作如下工作,申请储存spr索引的全局变量(就是在#include 区的下边输入new 变量名),我们不妨把变量名定为exp,然后,在插件plugin_precache过程中敲入exp = precache_model("sprites/zerogxplode.spr")这样,zerogxplode.spr(这是一个比较不错的爆炸spr文件)的spr索引就存储在了exp变量里。下面,我们开始完善这个message:
message_begin(MSG_BROADCAST,SVC_TEMPENTITY)
write_byte(3)
write_coord(x坐标)
write_coord(y坐标)
write_coord(z坐标)
write_short( exp )
write_byte(20)
write_byte(10)
write_byte(0)
message_end()

这样,一个爆炸效果将在坐标(x,y,z)处被创建,并以每秒10贞,2倍于自身spr大小的形式播放。为了让大家更完整的看到源代码,我把整个过程写出来,规则是这样:当玩家在控制台中输入expme,则自己瞄准的地方会产生一个爆炸效果,当然,是不伤人的。
#include <amxmod>
new exp   //申请全局变量exp

public plugin_init(){
register_plugin(" 创建爆炸 ","0.1","Hydralisk")//注册插件
register_clcmd("expme","h_expme") //注册控制台命令"expme", 当有人输入这个命令,则执行脚本中的 h_expme过程
return PLUGIN_CONTINUE
}

public plugin_precache(){   //这个就是我刚才说的plugin_precache过程
exp = precache_model("sprites/zerogxplode.spr") //预存储spr文件 zerogxplode.spr并将spr索引存储在exp变量里。
}

public h_expme(id){    //当有人输入"expme"时,这个过程将被触发,玩家的索引将被保存在头变量id里
new ori //申请3位数组变量ori
get_user_origin(id,ori,3) //获取玩家正在瞄准的位置,并按 x坐标,y坐标,z坐标存储在ori变量里
message_begin(MSG_BROADCAST,SVC_TEMPENTITY)
write_byte(3)
write_coord(ori)//x坐标
write_coord(ori)//y坐标
write_coord(ori)//z坐标
write_short( exp )   //spr索引
write_byte(20)   //20×0.1 = 2倍于原spr文件 的爆炸的大小
write_byte(10)   //每秒钟播放贞数
write_byte(0)      //标识为:正常爆炸
message_end()
}

第二部分,message对事件的操作。学习这部分,您最好也需要有一定的英文基础,不过本部分对英文的要求没有前面那部分对英文的要求那么多。如果您不会英文,也可以参看别人的源代码。
所谓对事件的操作,就是CS内部集成了很多事件,例如死亡消息DeathMsg(一个人把另外一个人打死后,屏幕右上角显示的消息)、屏幕震动ScreenShake、屏幕渐变ScreenFade(例如闪光弹爆炸后,玩家屏幕变成白色)、视场改变SetFov(例如AWP开镜后,远处的东西变大,就是改变了视场)、左侧图标StatusIcon(屏幕左侧“购物手推车”、“C4”、“人质释放点”、“VIP逃逸点”等图标都由此控制)……
其中绿色的部分为“事件名”,所有的CS事件名以及其内容都可以在nwb13曾经发的 【分享】关于事件等内容的参考资料 中找到。

我们先熟悉一下用message对事件操作的格式:
①        创建单人事件、

message_begin(MSG_ONE,get_user_msgid("事件名"),{0,0,0}, 玩家id)
write_...
….
message_end()

② 创建全局事件

message_begin(MSG_ALL,get_user_msgid("事件名"))
write_...
….
message_end()

所谓单人事件,就是这个事件是对单个人操作的事件。CS编写者定义事件的时候,已经确定了这个事件是单人事件还是全局事件。所以我们不能随便更改事件的性质,否则会引起服务器崩溃(“崩溃”只得是CS的服务器突然退出CS,对计算机没有太大影响)。我们一般可以凭感觉确定某一个事件是单人事件还是全局事件。例如,屏幕渐变,只对某个人的屏幕进行操作,使他的屏幕变白或者变黄或者变黑,所以这个事件就是单人事件;再例如,死亡消息,这个事件任何人都能看得到,所以这个事件就是一个全局事件。如果实在无法确认,那么就得自己试了。
下面我们举个例子,在这个例子中,当OP在控制台中输入"hy_fakekill 玩家名"<回车>后,那个被定义的玩家将会被OP“杀死”5次,其中用ak47爆头1次,m4a1杀死一次,刀爆头3次,当然,这个“杀死”不是真的杀死,那个玩家并不会死掉,只是屏幕的右上角显示被杀他被OP死5次。
首先,我们在前面所说的nwb13文章中的cs_event.xls文件中找到了DeathMsg的用法:

Message: DeathMsg
Argument Order: byte byte byte string
Description of Arguments: 1: Killer ID, 2: Victim ID, 3: Headshot, 4:Weapon Name

Message就是事件名, Argument Order 决定了message_begin和message_end之间的write_类型,Description of Arguments 表示第n个事件中的参数的作用。例如DeathMsg的事件内容为
write_byte()
write_byte()
write_byte()
write_string()
第一个byte代表杀人者的ID,第二个byte代表受害者的ID,第三个byte代表是否爆头,第四个代表string是武器名称。这样,DeathMsg的内容就应该是:

message_begin(MSG_ALL,get_user_msgid("DeathMsg"))
write_byte(killer)
write_byte(victim)
write_byte(0) // 或者是1
write_string("武器名")
message_end()

我们来把整个过程写完。

#include <amxmod>
#include <amxmisc>

public plugin_init(){
register_plugin("Kill","0.1","Hydralisk")
register_clcmd("hy_fakekill","fakekill",ADMIN_LEVEL_D," <victim name or #id>")
return PLUGIN_CONTINUE
}

public fakekill(id, level, cid){
if (!cmd_access(id,level,cid,2)) return PLUGIN_HANDLED   //检查执行权限
new arg
read_argv(1,arg,32)// 获得 “玩家名” 参数
new player = cmd_target(id,arg,3) // 获得 受害者的 id
if (!player) return PLUGIN_HANDLED //检测是否有这个玩家
// 开始操作事件
message_begin(MSG_ALL,get_user_msgid("DeathMsg"))
write_byte(id)
write_byte(player)
write_byte(1)
write_string("ak47")
message_end()

message_begin(MSG_ALL,get_user_msgid("DeathMsg"))
write_byte(id)
write_byte(player)
write_byte(0)
write_string("m4a1")
message_end()
for (new i=0; i<3; i++){
message_begin(MSG_ALL,get_user_msgid("DeathMsg"))
write_byte(id)
write_byte(player)
write_byte(1)
write_string("knife")
message_end()
}

return PLUGIN_HANDLED
}

如果有语句不通、错别字、不理解的地方,敬请提出

Hydralisk 发表于 2005-7-15 10:58:18

有点问题。。Test.

QQ8 发表于 2005-7-15 13:15:16


不是一下子就能看懂

Hydralisk 发表于 2005-7-15 13:50:52

有不懂得地方尽管提。而且我还没写完。

nwb13 发表于 2005-7-15 15:31:30

message_begin(MSG_ONE, SVC_TEMPENTITY,{0,0,0},玩家id)
中SVC_TEMPENTITY和{0,0,0}的意思是?

Hydralisk 发表于 2005-7-15 15:35:55

SVC_TEMPENTITY代表消息类型为“临时实体”其实所有的效果都是临时创建的实体,然后效果的寿命到了以后,实体就被删除。{0,0,0} 这个,因为那个参数没有用,所以就用{0,0,0}占一下位

明天我继续写message和事件(event)的关系。:)

BoeZombie 发表于 2005-7-15 20:56:07

:spiderman 偶只是飘过

Hydralisk 发表于 2005-7-15 21:02:47

。。。。。。

解脱 发表于 2005-7-20 20:33:12

支持拉啊`不错

kitshmily 发表于 2005-7-26 04:28:33

如雾里看花,似懂非懂!
页: [1] 2 3
查看完整版本: 【教程】关于message(重要课程!)