作者laechan (小太保)
看板mud
标题[心得] 怪物一般掉落物虚拟化
时间Wed Jul 31 14:53:37 2013
先说一个概念,各 mud 几乎都有技能系统,其使用的栏位也几
乎都是 skill 这个栏位,例如..
me->set("skill/barefist",100);
me->add("skill/barefist",200);
me->delete("skill/barefist");
me->query("skill/barefist");
现在假设从前从前从前,技能是「实体物件」,而身上某技能
的技能值多少=身上带了多少该技能的物件数。
那麽从实体物件的增减→技能值的增减,就是所谓虚拟化的过
程。
=======================================================
传统上,要撰写打死什麽怪物会掉什麽东西,一般是先写好该
物品(物件),然後设定怪物身上有这个东西,则玩家打死怪物
时物品自然掉落、或被玩家捡起如 get all from corpse。
那假设今天怪物的一般掉落物多到几百种,而且每个都可堆叠
,则允许玩家储存这些资料时就会造成资料档肥大、以及登入
时载入物品的 loading 过重。
可堆叠
http://www.wmon.com.tw/RO/photo/window/guide_ui05.gif

解决的方法很多(例如仿 shop 做法),这里分享其中一种。
首先,每只怪物的完整档名都是由目录+档名组成,而一只怪
物可设定会掉多种物品各自的掉落机率,也就是说:
{ 路径, 档名, 掉落物, 机率 } 是一串有效识别集合。
依上面的东西来决定物品掉落物设定集资料库的资料结构,就
是如下的例子
mapping drop_data=
([
// 第一层: 目录
"/area/maintown/mob/":([
// 第二层: 小黑狗的档名(无.c)
"black_dog":([
// 第三层: 掉落物与其机率
"犬齿":30,
"狗肉":10,
.
.
]),
]),
]);
那麽,一个很直觉的想法就是,当玩家打死小黑狗时,
在怪物的 die() 函数区一定会有读资料库的段落如下
玩家 被打死的怪物档名
drop_sys->check_drop( ppl, base_name(mob));
这个 object drop_sys 就是指怪物掉落物管理系统,
而这个系统里就宣告了如上的 mapping 资料。
这时候 check_drop 函数的内容就大致如下
int check_drop(object ppl,string mob_file)
{
string *drops=([]);
string mob_path,tmp,ob_name;
int s;
tmp=mob_file;
s=strlen(mob_file);
while(s-->0)
{
if(mob_file[s..s]="/")
{
mob_path=mob_file[0..s];
mob_file=tmp[s+1..strlen(tmp)-1];
}
}
// 将 "/area/maintown/mob/black_dog" 拆成
// "/area/maintown/mob" 及 "black_dog"
// 则马上就可判断该怪物是否有设定掉落物品
if(!drop_data[mob_path]) return 1;
if(!drop_data[mob_path][mob_file]) return 1;
// 通过这里代表该怪物有设定掉落物品,则以仿
// RO 的物品掉落为例
drops=keys(drop_data[mob_path][mob_file]);
foreach(ob_name in drops)
{
// 当判断到 所设定的掉落机率 > random(100) 时
if((int)drop_data[mob_path][mob_file][ob_name]>random(100))
ppl->get_drop(ob_name);
}
return 1;
}
所谓仿 RO 指的是打死 RO 的怪物会掉不只一种物品,而且
每种物品的掉落机率彼此是独立的。
而 get_drop 就依各家 mud 的写法不同而有不同。假设今天
是将资料放在玩家资料栏 obs 上面并仿技能资料的话,大致
如下..
int get_drop(string ob_name)
{
add("obs/"+ob_name,1);
write("你得到了一个"+ob_name+"!\n");
return 1;
}
或许你会说那就直接 add("obs/"+ob_name,1); 就好了为什
麽还要刻意呼叫函数来做?这是因为函数可以做一些弹性的
设计,例如..
int get_drop(string ob_name)
{
// 只有玩家身上携带的
该物总数小於 99 才会实际增加
if((int)query("obs/"+ob_name)>=99)
{
write(HIR"你已经携带了 99 个以上的"+ob_name+"了!"NOR"\n");
return 1;
}
// 当玩家没这东西时,只有玩家身上携带的
物品种类数小於 99 才会实际增加
if(!query("obj/"+ob_name) && sizeof(keys(query("obs")))>=99)
{
write(HIR"你已经携带了 99 种以上的物品,不能再带任何新物品了!"NOR"\n");
return 1;
}
// 其它弹性判断例子,例如虽执行到可掉落拳法秘笈,但是有设定
// 拳法根基(技能 barefist)必须达到 500 才可以取得时就不让他取得
if(ob_name=="barefist tips" && query("skill/barefist")<500)
return 1;
.
.
add("obs/"+ob_name,1);
write("你得到了一个"+ob_name+"!\n");
return 1;
}
而既然可以写 get_drop 函数,自然也可以写其它函数来处
理 obs 这个栏位的资料。
然後,玩家打到怪物掉落物时,一定会想看自己身上有哪些
掉落物,以及其数量各多少,假设观看的指令叫 ob,如下..
> ob
你的物品栏带着 9 种物品:
╔══════════╦══════════╦══════════╗
║ 1.牙齿 ( 10)║ 2.尾巴 ( 95)║ 3.翅膀 ( 10)║
║ 4.魔物心脏 ( 98)║ 5.硬角 ( 45)║ 6.外皮 ( 84)║
║ 7.尖刺 ( 39)║ 8.鼻环 ( 99)║ 9.大钳 ( 35)║
╚══════════╩══════════╩══════════╝
其程式段如下
msg="╔══════════╦══════════╦══════════╗\n";
keys_obs=keys((mapping)me->query("obs"));
i=0;
foreach(ob_name in keys_obs)
{
i=i+1;
msg+=sprintf("║%2d.%10s (%3d)",i,ob_name,
me->query("obs/"+ob_name));
if(i%3==0)
msg+="║\n";
}
msg+="╚══════════╩══════════╩══════════╝\n";
而当玩家想要将物品卖给商店时,至少要有该物品的单价等
资料,这就是另一个物品设定集资料库的内容,最简单的物
品资料库如下..
mapping obs_data=
([
// 第一层: 物品名字
"狗肉" :([
// 第二层: 设定资料
"value":10, // 比方十文钱
"cant_sell":1, // 比方有设定该参数代表不能卖
.
.
]),
]);
则卖给商店时
if(obs_data[ob_name]["cant_sell"])
{
write(HIR"你不能将"+ob_name+"卖给商店喔!"NOR"\n");
return 1;
}
me->add("obs/"+ob_name,-1);
v=(int)obs_data[ob_name]["value"];
me->add("wealth",v);
write("你卖掉一个"+ob_name+"得到了 "+v+" 文钱。\n");
到这里,物品就可被打到、可观看、也可卖掉了。
本系统的重点
1.需设定适当的资料结构(各家做法不同)
2.给玩家的指令、以及给 wiz 使用的指令要分开
=> 这纯粹是个人经验,分开比较好。但基本上它们都是对
同一个资料库做处理
3.要先评估好日後的设定规模。规模越小设计可越弹性,规模
越大,设计要越谨慎并最好有完整的前期测试(以发现问题)
4.要经常以日後易於增删、易於修改、易於维护的思考角度去
设计系统与指令
5.当设定量达到一定规模时要做一下资料档的备份
本系统的好处(不管是哪一家 mud)
1.减少实体物件占用记忆体及玩家资料档的空间
2.掉落物品资料不管是要读取资料还是做增删改均十分容易
3.可方便控管玩家身上的怪物掉落物品
a.集中资料库管理(且易於备份保存)
b.物品资料变更容易,一变更即套用(如价格)
c.容易做相关必要限制(如携带量)
d.可将资料库 export 结果释出给玩家,方便玩家制作打
怪掉落物品资料
4.几乎不需编写各物品的实体物件,节省时间及宝贵的人力
以上一点心得,跟大家分享,其它细节就不赘述。
Laechan@Sanc
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 210.61.157.53
1F:推 pssjim :推一下 114.46.233.70 07/31 19:52
2F:→ takomalu :收集怪物掉落素材 然後做出装备 106.187.98.173 08/06 00:13