找回密码
 注册
搜索
查看: 6211|回复: 19

教你如何看懂LPC(二)

[复制链接]
门派:不明
发表于 2012-4-13 20:18:50 | 显示全部楼层 |阅读模式
今天,我们来了解一下作为mud 世界里重要的组成部分——npc

在选取例子的时候,我很是纠结了一翻,sj2002中如此众多的npc 到底应该选取哪个为样本呢?灵光一闪,我有了一个主意,“霍都” 这个新人杀手,恶贯满盈、手上沾满了新人的鲜血。现在我们就来了解一下,究竟wiz 当时是怎样创造出这么一个恶心又经典的人物。通过对“霍都”了解,让我们从一个侧面走进当事wiz 的内心世界,去探究一下这个wiz 的阴暗与险恶(呵呵,玩笑话)

-----------------------------------------------------------------------------------------------------------------------------------------
// huo.c 何师我.霍都
// by snowman 12.feb.98
// Modify by Looklove 2000/10/07

#include <ansi.h>
inherit NPC;
string ask_me();
void check_skills(object ob);
void waiting(object dest);
void checking(object dest);
void do_back();
void do_kill(object dest);
void do_weapon();
void change_huo();

void create()
{
        if (clonep()) tell_room(environment(),
                HIY +"霍都转过墙角忽然不见了,接着走出来一个奇丑无比的乞丐。\n\n" NOR);
        set_name("何师我", ({"he shiwo", "he", "shiwo"}));
        set("gender", "男性");
        set("title", "丐帮第十九代弟子");
        set("age", 35);
        set("unique", 1);
        set("per", 13);
        delete("huodu");
        set("location", 1);
        set("long", "只见他身披一件宽大破烂的黑衣,手持一根酒杯口粗细的铁杖,满头\n"+
                        "乱发,一张脸焦黄臃肿凹凹凸凸的满是疤痕,背上负着五只布袋,原\n"+
                        "来是一名五袋弟子。\n");

        set("attitude", "friendly");
        create_family("丐帮", 19, "弟子");
        set("str", 23);
        set("int", 24);
        set("con", 22);
        set("dex", 27);
        set("per", 12);
        set("chat_chance", 35);
        set("chat_msg", ({ (: random_move , }));
        set("max_qi", 700);
        set("max_jing", 700);
        set("eff_jingli", 500);
        set("combat_exp", 150000);
        set_skill("parry", 60);
        set_skill("force", 60);
        set_skill("dodge", 60);
        set_skill("staff", 60);
        set_skill("huntian-qigong", 60);
        set_skill("tianshan-zhang", 60);
        set_skill("xiaoyaoyou", 50);
        set_skill("suohou-shou", 50);
        set_skill("hand", 50);
        map_skill("force", "huntian-qigong");
        map_skill("dodge", "xiaoyaoyou");
        map_skill("hand", "suohou-shou");
        map_skill("staff", "tianshan-zhang");
        prepare_skill("hand", "suohou-shou");
        set("inquiry", ([
                "霍都"  : (: ask_me ,
                "丐帮" : "我们丐帮是天下第一大帮!",
                "金轮法王" : "你在说什么啊?",
                "马光佐" : "你在说什么啊?",
                "尹克西" : "你在说什么啊?",
                "尼摩星" : "你在说什么啊?",
        ]));
        setup();
        if (clonep())
        {
                reincarnate();
                do_weapon();
        }
        remove_call_out("change_huo");
        if(clonep()) call_out("change_huo", 900);
}

void do_weapon()
{
        object armor, weapon, *ob, me = this_object();

        ob = all_inventory(me);

        foreach (object item in ob) destruct(item);
        if (query("huodu"))
        {
                armor = new(ARMOR_D("pao2"));
                weapon = new(__DIR__"obj/txs");
        }
        else
        {
                armor = new(ARMOR_D("cloth"));
                weapon = new(BINGQI_D("gangzhang"));
        }
        armor->move(me);
        armor->wear();
        weapon->move(me);
        weapon->wield();
        add_money("silver", 50);
}

nosave int init_flag = 0;

void init()
{
        object ob;

        ::init();
        if (init_flag) return;
        if (living(this_object()) && interactive(ob = this_player()) && visible(ob))
        {
                init_flag = 1;
                call_out("greeting", 1, ob);
        }
}

void greeting(object ob)
{
        init_flag = 0;
        if (ob && present(ob, environment()))
        {
                if (query("huodu") && ob->query("combat_exp") > 100000) check_skills(ob);
                else if (present("yuzhu bang", ob))
                {
                        object me = this_object();

                        message_vision(BLU"$N突然拦在$n面前,眼睛直盯着$n手里的玉竹棒!\n"NOR,me,ob);
                        change_huo();
                        ob->add_busy(2);
                        do_kill(ob);
                }
        }
}

string get_user_place()
{
        object *obs = users(), ob, room;
        string room_name;

        ob = obs[random(sizeof(obs))];
        if (room = environment(ob)) room_name = file_name(room);

        if (
        !room ||
        wiz_level(ob) ||
        ob->is_ghost() ||
        strsrch(room_name,"/d/") < 0 ||
        !strsrch(room_name, "/d/wizard/") ||
        !strsrch(room_name, "/d/death/") ||
        !strsrch(room_name, "/d/wuguan/")
        )
                return 0;

        return room_name;
}

void do_back()
{
        string room;

        remove_call_out("do_back");
        if (!stringp(room = get_user_place())) move("/d/city/kedian");
        else move(room);

        tell_room(environment(), query("name")+"快步走了过来。\n");
        set_leader(0);
}

string ask_me()
{
        object ob;
        ob=this_player();

        if (ob->query("combat_exp") < 100000) return "小孩子,你自己的名字知道怎么写吗?别问东问西的。";
        else
        {
                if (query("huodu"))
                {
                        check_skills(ob);
                        return "嘿嘿,霍都就是本王子,来耍两套猴戏给我看看吧!";
                }
                else
                {
                        switch(random(4))
                        {
                                case 0 : return "不知道。"; break;
                                case 1 : return "我可不认识这个人。"; break;
                                case 2 : return "谁是霍都啊?"; break;
                                case 3 : change_huo();
                                        do_kill(ob);
                                        return "嘿嘿,霍都就是本王子,来耍两套猴戏给我看看吧!\n";
                                break;
                        }
                }
        }
}

void change_huo()
{
        object *ob;

        remove_call_out("change_huo");

        tell_room(environment(), HIY +"突然何师我阴阴一笑,伸手撤去身上的肮脏布衣,又在脸上一抹,竟然\n"+
                "转眼就变成了一位身着锦袍、风度翩翩的中年公子。\n\n" NOR);
        set("title", "蒙古王子");
        set("long", "只见他身穿白边青色长袍,手拿摺扇,作贵公子打扮,脸上一股傲狠之色。\n");
        set_name("霍都", ({"huo du", "huo", "du"}));
        set("shen", -12000);
        set("per", 25);
        set("huodu", 1);
        set_skill("parry", 100);
        set_skill("force", 100);
        set_skill("dodge", 100);
        set_skill("sword", 100);
        set_skill("songshan-qigong", 120);
        set_skill("songshan-jian", 120);
        set_skill("xiaoyaoyou", 120);
        set_skill("suohou-shou", 120);
        set_skill("hand", 100);
        map_skill("force", "songshan-qigong");
        map_skill("dodge", "xiaoyaoyou");
        map_skill("hand", "suohou-shou");
        map_skill("sword", "songshan-jian");
        prepare_skill("hand", "suohou-shou");
        set("combat_exp", 300000);
        set("max_qi", 1500);
        set("max_jing", 1300);
        set("eff_jingli", 1400);
        set("jiali", 50);
        reincarnate();
        set("chat_chance_combat", 20);
        set("chat_msg_combat", ({ (: perform_action, "sword.feiwu" }));
        do_weapon();
        if (!environment()->query("no_fight") && !environment()->query("sleep_room"))
        {
                ob = all_inventory(environment());
                foreach (object item in ob) {
                        if (!userp(item)) continue;
                        if (!visible(item)) continue;
                        if (item->query_temp("block_msg/all")) continue;
                        if (item->query("combat_exp") < 100000) continue;
                        if (item->query_temp("user_type") == "worker") continue;
                        COMBAT_D->do_attack(this_object(), item, query_temp("weapon"), 1);
                }
        }
        remove_call_out("create");
        if (clonep()) call_out("create", 300+random(200));
}

void kill_ob(object ob)
{
        if (!query("huodu")) change_huo();
        ::kill_ob(ob);
}

void reset()
{
        if (clonep()) do_back();
}

#include "killer.h";

评分

1

查看全部评分

门派:不明
 楼主| 发表于 2012-4-13 21:07:08 | 显示全部楼层
实在是太长了,只好分段了。由于这不是一个简单的npc,里面有些内容目前对没有lpc 基础的朋友来说比较晦涩难懂,我只选取一部分进行讲解。

// huo.c 何师我.霍都 —— 文件名 huo.c 位于 /d/fuzhou/npc

// by snowman 12.feb.98 —— 创建wiz 大名鼎鼎的 snowman (创建时间 98年2月12日)

// Modify by Looklove 2000/10/07 —— 后经wiz looklove 于2000年10月7日修改

(这里说句题外话,以前的wiz 还是遵循了良好的code 书写习惯。)
好了,大家可以对上面两位吐槽了

if (clonep()) tell_room(environment(),
                HIY +"霍都转过墙角忽然不见了,接着走出来一个奇丑无比的乞丐。\n\n" NOR);
  —— 这个是大家经常看到的 霍都变身为何师我

set_name("何师我", ({"he shiwo", "he", "shiwo"}));
        set("gender", "男性");
        set("title", "丐帮第十九代弟子");
        set("age", 35);
        set("unique", 1);
        set("per", 13);
  —— 这里在对npc 的基本属性进行定义

delete("huodu"); —— 这个很严谨,不会出现 一霍一何的bug

set("str", 23);                 臂力 23
        set("int", 24);         悟性 24
        set("con", 22);        根骨 22
        set("dex", 27);        身法 27
—— 大家加加看,总和96 啊! 坑爹有没有! 众多npc 的4围都大于80,这就是为什么我们被打得跟孙子似的原因,特别是强调先天属性的时候

if(clonep()) call_out("change_huo", 900);  —— 如果何师我处于存续状态,就以900单位时间的延时呼叫 change_huo 模块,好了 杀手霍 就要登场了!!!

让我们直接跳到change_huo 模块

tell_room(environment(), HIY +"突然何师我阴阴一笑,伸手撤去身上的肮脏布衣,又在脸上一抹,竟然\n"+
                "转眼就变成了一位身着锦袍、风度翩翩的中年公子。\n\n" NOR);
—— 变身了、变身了,美少女战士水冰月! 哦,不对是霍都

set_skill("parry", 100);                  基本招架 100
        set_skill("force", 100);          基本内功 100
        set_skill("dodge", 100);        基本轻功 100
        set_skill("sword", 100);         基本剑法 100
        set_skill("songshan-qigong", 120);  嵩山气功  120
        set_skill("songshan-jian", 120);       嵩山剑法  120
        set_skill("xiaoyaoyou", 120);          逍遥游      120
        set_skill("suohou-shou", 120);        锁喉手      120
        set_skill("hand", 100);                 基本手法     100
—— 这孙子其实功夫不高

map_skill("force", "songshan-qigong");
        map_skill("dodge", "xiaoyaoyou");
        map_skill("hand", "suohou-shou");
        map_skill("sword", "songshan-jian");
        prepare_skill("hand", "suohou-shou");
—— 万恶的wiz 对他进行了技能准备

set("combat_exp", 300000);    exp 300k
        set("max_qi", 1500);        qi  1500
        set("max_jing", 1300);     jing 1300
        set("eff_jingli", 1400);     jingli 1400
        set("jiali", 50);                 jiali 50
—— 英雄们上啊,这孙子也就300k 而且技能还不满

if (!environment()->query("no_fight") && !environment()->query("sleep_room"))
        {
                ob = all_inventory(environment());
                foreach (object item in ob) {
                        if (!userp(item)) continue;
                        if (!visible(item)) continue;
                        if (item->query_temp("block_msg/all")) continue;
                        if (item->query("combat_exp") < 100000) continue;
                        if (item->query_temp("user_type") == "worker") continue;
                        COMBAT_D->do_attack(this_object(), item, query_temp("weapon"), 1);
                }
        }
        remove_call_out("create");
        if (clonep()) call_out("create", 300+random(200));
}

这一段是主精华的部分了,(!environment()->query("no_fight") && !environment()->query("sleep_room")) —— 如果你待在安全区或者睡房,这孙子就不会把你列入选取范围,如果exp<100k 或者你是工匠,他也不来找你麻烦,除此之外的所有id 随机选择

COMBAT_D->do_attack(this_object(), item, query_temp("weapon"), 1);  凶残地开始攻击了

   if (clonep()) call_out("create", 300+random(200)); 如果没选到 那就在300-500 单位时间内再变身回去
门派:不明
 楼主| 发表于 2012-4-13 21:11:46 | 显示全部楼层
看到这,大家一定要问了,没见他叫杀啊,我怎么就被干掉了呢?

最后一句 “#include "killer.h";”

在同一目录下 还有一个killer.h 文件,这是让大家惨死的元凶所在
----------------------------------------------------------------------------------------------
void check_skills(object ob)
{
        mapping skl;
        int *slevel;
        int counter;

        if (environment()->query("no_fight") || ob->query_temp("user_type") == "worker") return;
        skl = ob->query_skills();
        if (!sizeof(skl)) return;
        slevel  = values(skl);

        counter = 0;
        foreach (int item in slevel) if (item >= 100) counter++;

        if (!random(10) && counter >= 3 && (ob->query("combat_exp") > 100000)) {
                set_leader(ob);
                do_kill(ob);
        }
}

void do_kill(object dest)
{
        object me = this_object(), env = environment();

        remove_call_out("do_kill");
        if (objectp(dest) && present(dest, env) && !dest->is_busy()
        && !env->query("no_fight") && !env->query("sleep_room")) {
                message_vision(HIR "$N对$n阴阴一笑:送上门的肥肉,"+RANK_D->query_rude(dest)+",陪大爷我练练吧!\n" NOR, me, dest);
                set_leader(dest);
                kill_ob(dest);
                dest->fight_ob(me);
                checking(dest);
        }
        else call_out("waiting", 2, dest);
}

void waiting(object dest)
{
        object me = this_object();

        remove_call_out("waiting");
        if (objectp(dest)) {
                if (dest->is_ghost()) {
                        call_out("do_back", 5+random(5));
                        return;
                }
                if (is_fighting() && present(dest, environment())) {
                        call_out("checking", 1, dest);
                        return;
                }
                if (living(me) && environment(dest)->query("no_fight")){
                        call_out("do_back", 2);
                        return;
                }
                if (dest->query_temp("user_type") == "worker") {
                        call_out("do_back", 2);
                        return;
                }
                call_out("waiting", 1, dest);
        }
}

void checking(object dest)
{
        object ob;

        remove_call_out("checking");
        if (!dest) return;
        if (!present(dest, environment())) {
                call_out("waiting", 2, dest);
                return;
        }
        if (!is_fighting(dest)) kill_ob(dest);
        if (is_fighting())
        {
                call_out("checking", 1, dest);
                return;
        }
        if (objectp(ob = present("corpse", environment()))
        && ob->query("victim_id") == dest->query("id") )
        {
                command("chat* kick corpse");
                tell_room(environment(), query("name")+"拍了拍身上的灰尘,快步走了出去。\n" NOR);
                call_out("do_back", 2);
                return;
        }
        call_out("waiting", 1, dest);
}

门派:不明
 楼主| 发表于 2012-4-13 21:14:27 | 显示全部楼层
  skl = ob->query_skills();
        if (!sizeof(skl)) return;
        slevel  = values(skl);

        counter = 0;
        foreach (int item in slevel) if (item >= 100) counter++;

        if (!random(10) && counter >= 3 && (ob->query("combat_exp") > 100000)) {
                set_leader(ob);
                do_kill(ob);
        }
如果 你的exp>100k 并且 有3项技能大于 100,那不要意思 就你了  

do_kill(ob)  —— 图穷匕现

  if (objectp(dest) && present(dest, env) && !dest->is_busy()
        && !env->query("no_fight") && !env->query("sleep_room")) {
                message_vision(HIR "$N对$n阴阴一笑:送上门的肥肉,"+RANK_D->query_rude(dest)+",陪大爷我练练吧!\n" NOR, me, dest);
                set_leader(dest);
                kill_ob(dest);
                dest->fight_ob(me);
                checking(dest);
  —— 最后说一句 打倒万恶的wiz!
门派:不明
发表于 2012-4-13 21:33:49 | 显示全部楼层
他是在哪里随机选取的user呢,然后是如何跑到那个user的身边呢?这块我没有找到啊。
门派:不明
 楼主| 发表于 2012-4-13 21:51:02 | 显示全部楼层
呵呵,把斑竹给引来了。
string get_user_place()
{
        object *obs = users(), ob, room;
        string room_name;

        ob = obs[random(sizeof(obs))];        对所有在线人物随机选取
        if (room = environment(ob)) room_name = file_name(room);    返回的房间为该人物所在房间

        if (
        !room ||                       如果room 文件无法找到
        wiz_level(ob) ||              如果该人物为wiz
        ob->is_ghost() ||            如果该人物 已死亡
        strsrch(room_name,"/d/") < 0 ||               对返回文件名进行有效性判断
        !strsrch(room_name, "/d/wizard/") ||          房间文件不在 /d/wizard/ 目录下
        !strsrch(room_name, "/d/death/") ||           房间文件不在/d/death/目录下
        !strsrch(room_name, "/d/wuguan/")            房间文件不在 "/d/wuguan/ 目录下
        )
                return 0;                          否则返回0

        return room_name;                    返回 房间文件名
}

void do_back()
{
        string room;

        remove_call_out("do_back");
        if (!stringp(room = get_user_place())) move("/d/city/kedian");    如果返回值是0 就去 扬州客店
        else move(room);                 否则 就来到玩家身边

        tell_room(environment(), query("name")+"快步走了过来。\n");      在该房间所有人可见,霍都来了
        set_leader(0);    开始判断目标是否符合 要求
}



评分

1

查看全部评分

发表于 2012-4-13 22:27:23 | 显示全部楼层
npc的天赋设置已经没有用了,底层已经把query_dex query_int这些函数重定义了

varargs int query_str(int post)
{
        int improve;
        object me=this_object();
       
        improve = query_skill("claw", 1) / 10;
        improve = MAX(improve,query_skill("cuff", 1) / 10);
        improve = MAX(improve,query_skill("finger", 1) / 10);
        improve = MAX(improve,query_skill("hand", 1) / 10);
        improve = MAX(improve,query_skill("strike", 1) / 10);
        improve = MAX(improve,query_skill("leg", 1) / 10);
        improve = MAX(improve,query_skill("unarmed", 1) / 10);
        improve +=sld_btyjw();
       
        if (post<2){
          if (userp(me))
                  return query("str") + (post?0:query_temp("apply/str")) +  improve;
          else
            return (query("is_head")?query("str"):19) + (post?0:query_temp("apply/str")) +  improve;
        }
        else {
          if(userp(me))
                  return query("str")*2 + (post!=2?0:query_temp("apply/str")) +  improve;
          else
            return (query("is_head")?query("str"):19)*2 + (post!=2?0:query_temp("apply/str")) +  improve;
        }
}
门派:不明
 楼主| 发表于 2012-4-13 22:32:39 | 显示全部楼层
master 发表于 2012-4-13 22:27
npc的天赋设置已经没有用了,底层已经把query_dex query_int这些函数重定义了

varargs int query_str(in ...

哇,连master 都来了

master 明显没看(一),我早说过了一切以 sj2002为准,你说的底层我又看不到。

另,来都来了,你也不给加点分,鼓励一下,我写这么多容易嘛。
门派:不明
发表于 2012-4-13 22:36:41 | 显示全部楼层
我说霍都来的那么迅速呢,原来是瞬移啊,这回看明白了。
master讲的那个天赋还是没明白啥意思。
门派:不明
发表于 2012-4-13 22:37:20 | 显示全部楼层
is_head是什么意思呢,如果不是is_head就是固定的19是么。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|书剑永恒MUD ( 闽ICP备14012032号|闽公网安备 35050202000162号 )

GMT+8, 2025-6-29 09:11 , Processed in 0.053331 second(s), 29 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表