NPC制作教学(最好有点插件基础在进来!

Home Home
<< 1 2 3 >>
跳页: (共 3 页)
引用 | 编辑 husano896
2011-07-03 11:32
楼主
推文 x18
所谓NPC 基本上就是"非玩家控制"的角色 例如常见的ZBOT 人质都是

要做个NPC角色 我们需要用到<amxmodx>和<engine>这两个模块

就在sma上方加入(若有了就别再加了)
复制程式
#include <amxmodx>
#include <engine>

接着 要写个制造NPC的function出来 并在plugin_init()里面加入会调用到的指令
复制程式
public plugin_init()
{
       register_clcmd("npc_create", "create_npc")       //这个是只要玩家在控制台打npc_create这指令 就会读取create_npc里面的指令
}
复制程式
public create_npc(id)
1.我们首先需要用到create_entity这个指令来建立一个物体
复制程式
       new ent = create_entity("info_target")       //创立一个物体出来 并让"ent"指向他

2.设定NPC的位置 可以有很多种用法 这里是将NPC建立在玩家的头上
复制程式
       new Float:origin[3]

       entity_get_vector(id,EV_VEC_origin,origin)
       origin[2] += 300.0
       entity_set_origin(ent,origin);

3.设定血量
复制程式
       entity_set_float(ent,EV_FL_takedamage,1.0)       //这里是让它变成可被攻击
       entity_set_float(ent,EV_FL_health,100.0)                     //这里是设定血量

有研究过NST原码的玩家都会好奇 为什么不要用DAMAGE_AIM呢
用过的人就会发现 攻击npc时会lag 尤其是很多只NPC在地图上时会特别明显

4.设定模组(范例是使用models/player/terror/terror.mdl)
复制程式
       //※记得在plugin_precache()里面加入你的模组噢!!
       entity_set_model(ent, "models/player/terror/terror.mdl")

5.设定名称(记住不要设中文!!)
复制程式
       entity_set_string(ent,EV_SZ_classname,"npc_terror")       //这里可以随便取 但是到后面会用到

6.设定大小(记住 不要调太大!! 不然会卡住)
复制程式
       new Float:maxs[3] = {16.0,16.0,36.0}       //这里越大 NPC所占的范围越大
       new Float:mins[3] = {-16.0,-16.0,-36.0}       //这里越小 NPC所占的范围越大
       entity_set_size(ent,mins,maxs)              //设定大小
       entity_set_int(ent,EV_INT_solid, 2)       //使NPC变为固体(不能穿透)

7.设定画格
复制程式
       entity_set_float(ent,EV_FL_animtime,2.0)
       entity_set_float(ent,EV_FL_framerate,1.0)       //动作速率 调太大动作会像疯子...
       entity_set_int(ent,EV_INT_sequence,0)              //调用的动作序号
8.让NPC会思考
复制程式
       entity_set_float(ent,EV_FL_nextthink,halflife_time() + 0.01)       //这里是设定成下次思考的时间为游戏时间+0.01秒时

9.丢到地上(就真的这样翻..)
复制程式
       drop_to_floor(ent)

10.设定NPC思考的东西
复制程式
在public plugin_init()里面加入
register_think("npc_id","npc_think")       //前面的npc_id换成你前面npc设的名字!!
随意找个地方加入
public npc_think(id)
{
       //看你要让NPC干嘛都扔在这里
       entity_set_float(id,EV_FL_nextthink,halflife_time() + 0.01)
}
※瘟腥提示(?):如果sma里面有中文字的话 记得转成UTF-8 No Bom的格式!!

进入游戏后 测试看看吧!!


下面附件是做好的范例 有问题欢迎发问

参考来源:https://forums.alliedmods.net/showthread.php?t=11756

本帖包含附件
档名: zip npc_test.rar   (2022-06-09 14:18 / 2 KB)   下载次数:292


献花 x8
引用 | 编辑 husano896
2011-07-03 11:33
1楼
  
要使NPC能在被伤害/击杀时有特殊效果 我们需要用到hamsandwich这模块

在sma最上方加入
复制程式
#include <hamsandwich>
#include <fakemeta> //2011.12.28修正(真晚- - 

在NPC创建的地方加入

为了确保伤害公式只会被读一次 要记得加记录项 像下面
复制程式
if (!g_hamnpc)       //记住!!g_hamnpc只能被放在function外面!!
{
       //这两串是让NPC读到你的伤害公式
       RegisterHamFromEntity(Ham_TakeDamage, ent, "fw_TakeDamage")
       RegisterHamFromEntity(Ham_TraceAttack, ent, "fw_TraceAttack")
       RegisterHamFromEntity(Ham_Killed, ent, "fw_Killed")
       g_hamnpc = 1
}
※如果读了好几次的话 电脑当机恕不退费(? 不知道怎么加欢迎PM我
并在plugin_init里面加入
复制程式
       //这两串是让玩家读到你的伤害公式
       RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
       RegisterHam(Ham_TraceAttack, "player", "fw_TraceAttack")
       //这里就不需要加Killed了 不然会读两次

当然 我们还要在下面加入对应的function才行
复制程式
public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type)
{
       if (victim==attacker)
              return HAM_IGNORED;

       if (!pev_valid(victim) || !pev_valid(attacker))
              return HAM_IGNORED;

       new classname[32]
       pev(victim,pev_classname,classname,31)
       if (equal(classname,"(你之前设的NPC名字)"))       //这里是检查被打的人是不是NPC
       {
              //看你要加啥都加在这边
              //有一点要注意 "非"玩家使用的指令不能加在这边 否则会有错误
              //例如 被攻击/攻击者是NPC 就不能使用 cs_get_user_team(victim) 或 cs_set_user_money(victim, ...)
              //当然 is_user_connected(回传玩家是否连接)这类的指令可以用
              //伤害的修改教学 可以看a78大的文章 http://bbs-mychat.com/reads.php?tid=829669
       }
       return HAM_IGNORED; 
}
复制程式
#define DMG_HEGRENADE (1 << 24)       //感谢fouury提醒
new cache_bloodspray, cache_blood       //血的spr 等等会用到
public plugin_precache()
{
       //读取spr
       cache_blood = precache_model("sprites/blood.spr")
       cache_bloodspray = precache_model("sprites/bloodspray.spr")
}
public fw_TraceAttack(victim, attacker, Float:damage, Float:direction[3], tracehandle, damage_type)
{
       if (victim==attacker)
              return HAM_IGNORED;

       if (!pev_valid(victim) || pev_valid(attacker))
              return HAM_IGNORED;

       new classname[32]
       pev(victim,pev_classname,classname,31)
       if (equal(classname,"(你之前设的NPC名字)"))       //这里是检查被打的人是不是NPC
       {
              //注意事项跟上面一样
              //get_tr/set_tr这类指令可以使用 可用来判定伤害部位/喷血位置
              //下面会有范例(饭粒?
              new body = get_tr2(tracehandle,TR_iHitgroup) //取得NPC被伤害的部位
              if (body == 1)       //爆头的情况下
              {
                     damage *= 4.0       //伤害四倍
                     SetHamParamFloat(3, damage)       //读取修改过后的伤害
              }

              new Float:Fend[3],end[3]
              get_tr2(tracehandle, TR_vecEndPos, Fend)       //在开枪的位置和被击中的位置画条线(我不知道怎么解释..)

              //This message will draw blood sprites at the end of the trace
              if (!(damage_type & DMG_HEGRENADE))       //如果不是被芭乐炸的
              {
                     end[0] = floatround(Fend[0])
                     end[1] = floatround(Fend[1])
                     end[2] = floatround(Fend[2])
                     create_block_sprites(end)       //在该位置显示喷血(不会有血迹)
              }
       }     
       return HAM_IGNORED;
}

create_block_sprites(const origin[3])
{
       // Show some blood :)
       message_begin(MSG_BROADCAST, SVC_TEMPENTITY) 
       write_byte(TE_BLOODSPRITE)
       write_coord(origin[0])
       write_coord(origin[1])
       write_coord(origin[2])
       write_short(cache_bloodspray)
       write_short(cache_blood)
       write_byte(75)
       write_byte(5)
       message_end()
}

复制程式
public fw_Killed(victim, attacker)
{
       //※跟上上方的说明一样 非玩家指令不能用 除非你能确定你用的人是玩家
       new classname[32]
     pev(victim,pev_classname,classname,31) 
       if (equal(classname,"(你之前设的NPC名字)"))       //这里是检查被打的人是不是NPC
       {
              if (is_user_connected(attacker))       //当攻击者是玩家时
              {
                     //你可以在这里加给玩家用的指令 例如加钱...加血
              }
       }
       return HAM_IGNORED
}
有兴趣的人 可以看下面从Ham_const里面拿来的说明(英文)
复制程式
        * Description:              Usually called whenever an entity gets attacked by a hitscan (such as a gun) weapon.
        *                                   Use the get/set tr2 natives in fakemeta to handle the traceresult data.
        *                                   Do not use a handle of 0 as a traceresult in execution, use create_tr2() from Fakemeta
        *                                   to pass a custom handle instead.  (Don't forget to free the handle when you're done.)
        * Forward params:       function(this, idattacker, Float:damage, Float:direction[3], traceresult, damagebits)
        * Return type:              None.
        * Execute params:       ExecuteHam(Ham_TraceAttack, this, idattacker, Float:damage, Float:direction[3], tracehandle, damagebits);
        */
       Ham_TraceAttack,
       
       /**
        * Description:              Usually called whenever an entity takes any kind of damage.
        *                                   Inflictor is the entity that caused the damage (such as a gun).
        *                                   Attacker is the entity that tirggered the damage (such as the gun's owner).
        * Forward params:       function(this, idinflictor, idattacker, Float:damage, damagebits);
        * Return type:              Integer.
        * Execute params:       ExecuteHam(Ham_TakeDamage, this, idinflictor, idattacker, Float:damage, damagebits);
        */
       Ham_TakeDamage,

这次说明可能比较难懂 多观察其他插件的使用方式吧
如果完全看不懂 建议你先学一点c++

题外话:这次的东西好多都忘了改为engine的用法><

2011.12.28:还是改回fakemeta好了 问题好多..(汗尤其是get_tr2的部分根本不能用(汗颜

献花 x4
引用 | 编辑 zdt
2011-07-03 12:54
2楼
  
请问可以做一个BOT出来吗?就是有分队的....

献花 x0
引用 | 编辑 zz12345zxc
2011-07-03 13:07
3楼
  
这是来实现 cs的灾厄之章吗? 话说 你现在已经做到哪了!

献花 x0
引用 | 编辑 冷场の飞天娘
2011-07-03 14:04
4楼
  
请尽快完成,

我真的很想了解这门技术 表情 ~~

虽然还没完成先推推啦~~

(花花完成再给),花花是人质! 表情

献花 x1
引用 | 编辑 HiNess
2011-07-03 14:05
5楼
  
之前看过一个NPC制作教学的POST(外国)
(很像这个post http://forums.alliedmods.net/showthread.php?t=11756...)

都是一些很难的英文(看不懂...)
终于有中文的教学^^

献花 x0
引用 | 编辑 小XC
2011-07-04 12:36
6楼
  
我应该可以学起来!= =!

献花 x0
引用 | 编辑 冷场の飞天娘
2011-07-04 20:09
7楼
  
我还是不太清楚这要怎么使用.......

重生点在哪里?

楼主提供的就是主插件?

如何使用?

需要他配其他插件吗?

指令是什么?

.....................等等........... 表情

献花 x0
引用 | 编辑 离之彦
2011-07-04 20:16
8楼
  
加油~~~~~~~

话说NPC真的很笨...

让您研究了不少时间哪...

献花 x0
引用 | 编辑 小XC
2011-07-04 20:43
9楼
  
奇怪
未啥我打npc_create的时候会跳出游戏阿到登入画面阿

献花 x0
引用 | 编辑 husano896
2011-07-05 09:22
10楼
  
下面是引用 飞天派 于 2011-07-04 20:09 发表的 : 到引言文
我还是不太清楚这要怎么使用.......

重生点在哪里?

楼主提供的就是主插件?

如何使用?

需要他配其他插件吗?

指令是什么?

.....................等等........... 表情




这篇是教"写"插件噢

献花 x0
引用 | 编辑 绝影华
2011-07-06 09:30
11楼
  
如果想拎玩家对NPC禁e有选单弹出

如何整出来

献花 x0
引用 | 编辑 husano896
2011-07-06 13:50
12楼
  
下面是引用 绝影华 于 2011-07-06 09:30 发表的 : 到引言文
如果想拎玩家对NPC禁e有选单弹出

如何整出来


new ent前面的地方加入判定条件就行了
[font=]ex:[font=]
[font=]if (cs_get_user_money(id) < 6000)[font=]return...

献花 x0
引用 | 编辑 绝影华
2011-07-06 16:24
13楼
  
下面是引用 husano896 于 2011-07-06 13:50 发表的 : 到引言文



new ent前面的地方加入判定条件就行了
[font=]ex:[font=]
[font=]if (cs_get_user_money(id) < 6000)[font=]return...

还是不明白-.-   例如我整了一个选单出来是


应该怎样加上去





public mostrarmenu(id)
{
        {
        new menu = menu_create("\y 商店:", "mostrar_cliente")
   
        menu_additem(menu, "\r Admin专用武器", "1", 0)
   
    menu_display(id, menu, 0)
        }
}

public mostrar_cliente(id, menu, item, Float:damage)
{
    new data[6], iName[64]
    new access, callback
   
    menu_item_getinfo(menu, item, access, data,5, iName, 63, callback)
   
    new key = str_to_num(data)
   
    switch(key)
    {
        case 1:{
            if(cs_get_user_money(id) >= 10)
            {
                    if (get_user_flags(id) & ADMIN_KICK)
                {
                    {
                            give_item(id, "weapon_m249")
                            cs_set_user_money(id,cs_get_user_money(id) - 10)
                        client_print(id, print_chat, "[商店]恭喜管理员成功购买了武器")
                        return PLUGIN_HANDLED
                    }
                }
                else
                {
                    client_print(id, print_chat, "[商店]你不够权限购买!")
                }
            }
            else
            {
                client_print(id, print_chat, "[商店]你不够金钱购买")
            }
               }
        }
    menu_destroy(menu)
    return PLUGIN_HANDLED
}

献花 x0
引用 | 编辑 husano896
2011-07-06 16:35
14楼
  
下面是引用 绝影华 于 2011-07-06 16:24 发表的 : 到引言文

还是不明白-.-   例如我整了一个选单出来是

应该怎样加上去

.......


噢 我误会你的意思了

是要碰到NPC后会叫出选单的话

就在plugin_init()里面加入register_touch("(你之前设定的NPC名字)", "player", "npc_touch")

并在下面加入

public npc_touch(ent,id){//(这里加入叫出商店的指令)}

献花 x0
引用 | 编辑 绝影华
2011-07-06 16:55
15楼
  
下面是引用 husano896 于 2011-07-06 16:35 发表的 : 到引言文



噢 我误会你的意思了

是要碰到NPC后会叫出选单的话

就在plugin_init()里面加入register_touch("(你之前设定的NPC名字)", "player", "npc_touch")

并在下面加入

public npc_touch(ent,id){//(这里加入叫出商店的指令)}

很多谢那么乐意回答我的问题

还有3个问题要问问  thx

怎可以把那个NPC变无敌?

,

如果是禁E才有选单弹出 , 而不是碰到 应该怎样改



如果那指令是say /shop  应该怎加上去

献花 x0
引用 | 编辑 tw2twtw
2011-07-06 18:52
16楼
  
entity_set_float(ent,EV_FL_takedamage,0.0)     //设定成不能被攻击就好了.... 表情

献花 x0
引用 | 编辑 fouury
2011-07-06 22:04
17楼
  
关于DMG_HEGRENADE那里好像忘了加上这个 表情

复制程式
#define DMG_HEGRENADE (1 << 24)
表情

献花 x0
引用 | 编辑 绝影华
2011-07-07 01:29
18楼
  
下面是引用 tw2twtw 于 2011-07-06 18:52 发表的 : 到引言文
entity_set_float(ent,EV_FL_takedamage,0.0)     //设定成不能被攻击就好了.... 表情



如果想令玩家对NPC禁E有选单弹出 , 而不是碰到 应该怎样改



如果那指令是say /shop  应该怎加上去

献花 x0
引用 | 编辑 杰;]
2011-07-07 18:27
19楼
  
哗==
很详尽而且解释得很清楚的教学
可是我也感到很难明白..
不过也谢谢楼主用心的教学

献花 x0
引用 | 编辑 honfai99
2011-07-08 21:05
20楼
  
可能做出一个好 Think 还是不能做出灾厄.. 我做的灾厄的 NPC 们都很容易卡住..

只要是弯路就会卡住在墙角... 做 waypoints 又怕他们只会行同一路径..

waypoints 的话就不会追踪玩家来攻击..

献花 x0
引用 | 编辑 husano896
2011-07-09 08:06
21楼
  
下面是引用 honfai99 于 2011-07-08 21:05 发表的 : 到引言文
可能做出一个好 Think 还是不能做出灾厄.. 我做的灾厄的 NPC 们都很容易卡住..

只要是弯路就会卡住在墙角... 做 waypoints 又怕他们只会行同一路径..

waypoints 的话就不会追踪玩家来攻击..


不一定噢

可以做成 以waypoints为主

看到人在跟踪

当人从视野中离开时 就移动最近的waypoint继续移动

献花 x0
引用 | 编辑 a7811311622
2011-07-09 12:47
22楼
  
唉…不是很看好这篇教学…
不是因为标题还是教的不好之类的问题…
而是目前有一堆人自从碰过NST的NPC后就一股脑儿想学怎么弄NPC…
明明插件都还没学过基础就想学NPC…根本是想一步登天…
会写插件的看完全部内容就知道前半部内容都是在说怎么制造物件…
但是没学过插件的光是前半段大概就不清楚在说什么了…

嘛…但是让会写插件的来解释插件原码基础…一堆人也不太会或不太想解释…
总觉得会写插件的人也是有问题就是了…(自婊?)

献花 x2
引用 | 编辑 史来姆
2011-07-09 17:52
23楼
  
嗯,我也蛮同意a78大的说法
我也是因为nst而研究npc呐...
我个人觉得npc是插件中难度较为颇高
现在弄出了npc灾厄,算是有点成就吧( 表情

我建议husano大你把题目改一下
免得吓到想学插件的新手
新手:"甚么嘛,插件都是这么难的啊QAQ,我不学了~"
↑这样的

献花 x0
引用 | 编辑 冷场の飞天娘
2011-07-09 20:32
24楼
  
下面是引用 史来姆 于 2011-07-09 17:52 发表的 : 到引言文
嗯,我也蛮同意a78大的说法
我也是因为nst而研究npc呐...
我个人觉得npc是插件中难度较为颇高
现在弄出了npc灾厄,算是有点成就吧( 表情  

我建议husano大你把题目改一下
免得吓到想学插件的新手
新手:"甚么嘛,插件都是这么难的啊QAQ,我不学了~"
↑这样的


"哇!好深奥!原来插件是如此高深的学问!我想要学表情 "

↑我

(虽然还没踏出地一步表情 )

献花 x0
引用 | 编辑 zxcvasd2
2011-07-09 23:36
25楼
  
husano大大喔

为什么在我学写npc的时候你不发这个post,
现在我学成了就发出来了 0.0 表情

话说这个post对新手npc入门还挺有用喔

献花 x0
引用 | 编辑 fouury
2011-07-10 00:02
26楼
  
下面是引用 史来姆 于 2011-07-09 17:52 发表的 : 到引言文
嗯,我也蛮同意a78大的说法
我也是因为nst而研究npc呐...
我个人觉得npc是插件中难度较为颇高
现在弄出了npc灾厄,算是有点成就吧( 表情

我建议husano大你把题目改一下
免得吓到想学插件的新手
新手:"甚么嘛,插件都是这么难的啊QAQ,我不学了~"
↑这样的

恩阿.表情
如果不懂.  直接接触此文章的话.  
下场就是被文字打的落花流水表情   (刘海都湿了...)
且可能会造成一种对插件的"永久"刻版印象(就是很复杂)  表情

所以这些想法根本全鉴于自己本身的学习心态了 表情

献花 x0
引用 | 编辑 784063999
2011-07-16 23:23
27楼
  
我觉得这个不是很难
有不少插件可以研究

献花 x0
引用 | 编辑 andyt0621
2011-07-17 14:11
28楼
  
哈哈..看来nst的NPC对插件手影响很大耶..
我也是看了nst的NPC才写了雷比亚和阿比隆 0.0

献花 x0
引用 | 编辑 文♂
2011-07-17 17:46
29楼
  
这文章真有用 已经学会了表情

但问题.....问题是我现在不会弄成一个主插件把全部npc集合表情

-------------------------------------

还有一个问题......

怎样设定npc拥有名字表情

献花 x0
<< 1 2 3 >>
跳页: (共 3 页)