使用MUDCORE框架从零开发LPMUD游戏:基础的物品和装备

《使用MUDCORE框架从零开发LPMUD游戏》系列内容,通过教程既能熟悉 MUDCORE 框架的使用,也能学习LPCMUD游戏的开发,版权所有 mud.ren。

物品和装备的开发其实和NPC类似,只是一方面定义一些通用的方法实现特定的功能由所有物品类继承,另一方面提前约定好参数的意义并在需要的地方实现功能。比如,NPC开发中约定hp属性为生命,当受到伤害或使用恢复药品时减少或增加数据,物品开发也是一样的思路,注意开发中通用功能模块一定要独立出来继承使用,不要写重复的代码。

物品

我们先实现物品公共模块inherit/item.c方便继承,宏定义为ITEM

/*****************************************************************************
Copyright: 2019, Mud.Ren
File name: item.c
Description: 物品功能公共接口
Author: xuefeng
Version: v1.0
Date: 2019-03-14
History:
*****************************************************************************/
inherit CLEAN_UP;
inherit DBASE;
inherit MOVE;
inherit NAME;

nosave int amount;

int is_item() { return 1; }

// allows an object to do self-maintenance
void reset()
{
    /*
    write_file(LOG_DIR + "reset", "[ITEM]->reset():" +
        sprintf("%-50s%s", file_name(this_object()), ctime(time()) + "\n"));
    */
}

int query_amount() { return amount; }

void destruct_me() { destruct(this_object()); }

void set_amount(int v)
{
    if (v < 1)
    {
        amount = 0;
        call_out("destruct_me", 0);
    }
    else
    {
        amount = v;
        set_temp("amount", v);
    }
}

void add_amount(int v) { set_amount(amount + v); }

varargs int move(mixed dest, int silent)
{
    object env, *inv;
    int i, total = 1;
    string file;

    if (::move(dest))
    {
        env = environment();
        if (objectp(env) && !query_temp("equip"))
        {
            file = base_name(this_object());
            inv = filter_array(all_inventory(env), (: !$1->query_temp("equipped") :));

            if (query_temp("amount"))
                total = (int)query_temp("amount");

            for (i = 0; i < sizeof(inv); i++)
            {
                if (inv[i] == this_object())
                    continue;
                if (base_name(inv[i]) == file)
                {
                    total += (int)inv[i]->query_temp("amount");
                    destruct(inv[i]);
                }
            }
            set_amount(total);
        }
        return 1;
    }
}

// does I can combine to an item in the object env ?
int can_combine_to(object env)
{
    object item;
    string file;

    file = base_name(this_object());
    foreach (item in all_inventory(env))
        if (base_name(item) == file)
            return 1;

    return 0;
}

// 物品使用效果
int do_effect(object me)
{
    msg("vision", "$ME使用了" + this_object()->name() + ",然而什么事都没发生!", me);
    return 1;
}

void setup()
{
}

这里实现了物品的基础方法,一方面继承了部分模块实现必要的功能,另一方面实现了物品数量控制类的方法。

然后实现标准的物品对象std/item/item.c,由所有物品类继承,宏定义为STD_ITEM,当前代码并不多:

/*****************************************************************************
Copyright: 2019, Mud.Ren
File name: item.c
Description: 游戏道具标准继承对象 STD_ITEM
Author: xuefeng
Version: v1.0
Date: 2019-03-15
History:
*****************************************************************************/
inherit ITEM;

void create()
{
    set_name("怪物铜币", ({"coin"}));
    set("long", "只有特殊的魔物才会拥有的铜币,可以卖了赚钱。");
    set("unit", "个");
    set("base_value", 20);
    set("value", 100);
}

然后细分不同类别的物品,继承标准物品并实现自己特色的功能,如药品、魔法道具等,这里不再给示例代码,具体参考std/item/下的代码。

装备

装备开发一样,先实现装备的通用模块功能inherit/equipment.c,宏定义为EQUIPMENT:

/*****************************************************************************
Copyright: 2019, Mud.Ren
File name: equipment.c
Description: 装备物品公共接口
Author: xuefeng
Version: v1.0
Date: 2019-03-14
History:
*****************************************************************************/
inherit ITEM;

int is_equipment() { return 1; }

int equip()
{
    object owner;
    mapping equip_info, equip_effect;
    string *status, gender;

    owner = environment();
    if (!owner || !owner->is_character())
        return 0;

    if (query_temp("equipped"))
    {
        return notify_fail("你已经装备着呢。\n");
    }

    if (!mapp(equip_info = query("equip_info")))
        return notify_fail("你无法装备这件物品。\n");

    if (arrayp(equip_info["vocation"]) && sizeof(equip_info["vocation"]) &&
         member_array(owner->query("vocation"), equip_info["vocation"]) == -1)
    {
        if ((equip_info["type"] == "weapon") && bitCheck(owner->query_skill(equip_info["weapon"]), 10))
        {
            ; // 可以装备
        }
        else if ((equip_info["type"] == "shield") && bitCheck(owner->query_skill("shield"), 10))
        {
            ; // 可以装备
        }
        else
            return notify_fail("你无法装备这件装备。\n");
    }

    if (owner->query_temp("equip/" + equip_info["type"]))
    {
        return notify_fail("你已经装备了同类型的装备啦。\n");
    }
    if (equip_info["lv"] > owner->query("lv"))
    {
        return notify_fail("你的等级不足以装备这件物品。\n");
    }
    if (equip_info["gender"] && owner->query("vocation") != "minstrel")
    {
        if (equip_info["gender"] == 1)
        {
            gender = "男性";
        }
        else
        {
            gender = "女性";
        }
        if (gender != owner->query("gender"))
        {
            return notify_fail("你的性别无法装备这件物品。\n");
        }
    }

    owner->set_temp("equip/" + equip_info["type"], this_object());
    equip_effect = query("equip_effect");
    status = keys(equip_effect);
    // 增加装备属性效果
    for (int i = 0; i < sizeof(status); i++)
        owner->add_temp("buff/attr/" + status[i], equip_effect[status[i]]);
    // 激发装备被动技能
    if (equip_info["weapon"])
    {
        owner->skill_effect(equip_info["weapon"], 1);
        owner->skill_effect("fist", 0);
    }
    else if (equip_info["type"] == "shield")
        owner->skill_effect("shield", 1);

    set_temp("equipped", 1);
    delete_temp("equip");
    return 1;
}

int unequip()
{
    object owner;
    mapping equip_info, equip_effect, owner_status;
    string *status;
    int equipped;

    owner = environment();
    if (!owner || !owner->is_character())
        return 0;

    if (!(equipped = query_temp("equipped")))
        return notify_fail("你目前并没有装备这样东西。\n");

    equip_info = query("equip_info");
    equip_effect = query("equip_effect");

    if (equipped)
    {
        owner->delete_temp("equip/" + equip_info["type"]);
        if (equip_info["weapon"])
        {
            owner->skill_effect(equip_info["weapon"], 0);
            owner->skill_effect("fist", 1);
        }
        else if (equip_info["type"] == "shield")
            owner->skill_effect("shield", 0);
    }

    if (mapp(equip_effect))
    {
        status = keys(equip_effect);
        owner_status = owner->query_temp("buff/attr");
        for (int i = 0; i < sizeof(status); i++)
            owner_status[status[i]] -= equip_effect[status[i]];
    }

    delete_temp("equipped");
    return 1;
}

// 装备前缀词(装备增加前缀效果)
void prefix()
{
    // todo
}

// 套装
void suit()
{
    // todo
}

因为装备也具有物品的基本属性,所以直接继承ITEM实现通用功能,然后再单独实现装备相关的功能。

同样为装备实现标准对象方便所有装备类继承使用,另外装备还细分武器和防具,相关代码在std/equipment/目录,这里不再演示。


在示例项目中,所有具体的物品和装备都在obj目录下,每种道具对应具体代码,这只是传统的写法,为了展示同样功能的不同实现方式,其实推荐做法是类似NPC,把数据统一管理,通过传参数来实例化不同的具体对象,这里暂不演示,有兴趣的玩家可以自己改造代码。

京ICP备13031296号-4