《使用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,把数据统一管理,通过传参数来实例化不同的具体对象,这里暂不演示,有兴趣的玩家可以自己改造代码。