分享一下利用gmcp配合mudlet实现mapper功能
关键代码改造如下 /feature/gmcp.c
#define GMCP_LOG 50
nosave int dump_gmcp_log();
#ifdef GMCP_LOG
nosave string* gmcp_log = ({});
#endif
private void log_gmcp(string msg)
{
#ifdef GMCP_LOG
gmcp_log = gmcp_log[<GMCP_LOG..] + ({ msg });
#endif
}
private varargs void send_gmcp(string package, string message, mixed* data...)
{
string pkg = lower_case(package);
string msg = package + "." + message;
if (sizeof(data)){
catch(msg += " " + json_encode(data[0]));
log_gmcp("Sending: " + msg);
efun::send_gmcp(msg);
}
}
void gmcp(string req) {
log_gmcp("Received: " + req);
}
static void init_gmcp()
{
if (!has_gmcp(this_player()))
return;
send_gmcp("Core", "Hello", ([ "name": MUD_NAME ]));
add_action("dump_gmcp_log", "gmcp");
}
#ifdef GMCP_LOG
static int dump_gmcp_log()
{
write(implode(gmcp_log, "\n") + "\n");
return 1;
}
#endif
varargs void process_gmcp(mapping attributes,string package, string message)
{
if (!package || !message) {
log_gmcp("Returning: "+package+"."+message);
return;
}
log_gmcp("Process: "+package+"."+message);
switch (lower_case(package+"."+message))
{
// Module core:------------------------------------------
case "room.info":
if (mapp(attributes))
send_gmcp(package, message, attributes);
return;
case "move.info":
if (mapp(attributes))
send_gmcp(package, message, attributes);
return;
default:
return;
}
}
user object 增加代码:
inherit "feature/gmcp";
setup内增加 ::init_gmcp();:
void setup()
{
// We want set age first before new player got initialized with
// random age.
update_age();
::init_gmcp();
::setup();
restore_autoload();
}
修改/cmds/std/go.c,以风云的go为例直接贴代码
#include <ansi.h>
#include <combat.h>
inherit F_CLEAN_UP;
mapping default_dirs = ([
"north": "北",
"south": "南",
"east": "东",
"west": "西",
"northup": "北边高处",
"southup": "南边高处",
"eastup": "东边高处",
"westup": "西边高处",
"northdown": "北边低处",
"southdown": "南边低处",
"eastdown": "东边低处",
"westdown": "西边低处",
"northeast": "东北",
"northwest": "西北",
"southeast": "东南",
"southwest": "西南",
"up": "上",
"down": "下",
"out": "外",
"enter": "里",
]);
void create() {
seteuid(getuid());
}
int drop_things(object me) {
int i, result;
object *inv;
object env;
env = environment(me);
inv = all_inventory(me);
result = 0;
for(i=0;i<sizeof(inv);i++){
if(inv[i]->query("no_drop") || inv[i]->query("equipped") || inv[i]->query("owner")
|| random(me->query_max_encumbrance()) > inv[i]->weight()) {
continue;
}
result = me->ccommand("drop "+inv[i]->query("id")) ? 1 : result;
}
if(result) {
message_vision("慌乱而去。", me);
return 1;
}
return 0;
}
int check_flee(object me, string arg) {
object *enemy;
int fp, bp, i, level;
fp = me->query_agi();
enemy = me->query_enemy();
i = sizeof(enemy);
while (i--) {
if( objectp(enemy[i]) && environment(enemy[i])== environment(me) && living(enemy[i]))
{
if (enemy[i]->query("possessed")) continue;
if (enemy[i]->query_temp("is_unconcious")) continue;
// Since x5 can usually kill 1, Let it not blocking x5.
if (enemy[i]->query("combat_exp")< me->query("combat_exp")/5) continue;
bp = enemy[i]->query_agi();
if (fp > bp*2) continue;
if (enemy[i]->is_busy())
bp = bp * 3/5;
level = F_LEVEL->get_level(me->query("combat_exp"));
if ( level <30) fp = fp*3;
else if (level < 40) fp = fp*2;
if((random(fp + bp) < bp)
|| enemy[i]->query_temp("block_all_escape"))
{
message_vision(YEL "$N向" + arg + "逃去!\n" NOR, me);
message_vision(RED "$N身影一闪,挡在了$n的面前!\n" NOR, enemy[i], me);
return 0;
}
}
}
return 1;
}
int main(object me, string arg) {
string dest, mout, min, dir;
object env, obj;
mapping exit,room_info;
env = environment(me);
room_info=([]);
if( !arg ){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你要往哪个方向走?\n");
}
if( me->over_encumbranced() ){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你的负荷过重,动弹不得。\n");
}
if( me->is_busy() ){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你现在忙得很,不能移动。\n");
}
if (stringp(me->query_temp("no_move"))){
me->process_gmcp(room_info,"Move","Info");
return notify_fail(me->query_temp("no_move"));
}
if(!env){me->process_gmcp(room_info,"Move","Info");
return notify_fail("你哪里也去不了。\n");
}
if(env->query_temp("lock_scene"))
{
if(time()<env->query_temp("lock_scene")+120){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你感觉到周围被一阵气场紧紧缩住,无法动弹。\n");
}
}
if( !mapp(exit = env->query("exits")) || undefinedp(exit[arg]) ) {
if( query_verb()=="go"){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("这个方向没有出路。\n");
}else{
me->process_gmcp(room_info,"Move","Info");
return 0;
}
}
// 在fy4里尚未用到此功能,需要时再说。
/* if( mapp(block = env->query("blocks"))&& blk=block[arg]) {
if( objectp(blocker = present(blk, env)) && living(blocker))
return notify_fail("这个方向的路被"+ blocker->name() + "挡住了 。\n");
}*/
dest = exit[arg];
if( !(obj = find_object(dest)) )
{
if (!load_object(dest))
{
me->process_gmcp(room_info,"Move","Info");
tell_object(me,"这间屋子已消失在虚空中...\n");
if (wizardp(me) && me->query("env/yesiknow"))
call_other(dest, "???");
return 1;
}
// call_other(dest, "???");
}
if( !(obj = find_object(dest)) ){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("无法移动。\n");
}
/* if (userp(me) && ANNIE_D->check_buff(me,"fugitive")>0
&& (obj->query("no_fight") || obj->query("no_death_penalty")))
return notify_fail("你身负重案,那些地方不敢收留你呀!\n");*/
if (env)
if (!env->valid_leave(me, arg) ) {
me->process_gmcp(room_info,"Move","Info");
return 0;
}
if( !undefinedp(default_dirs[arg]) )
dir = default_dirs[arg];
else if (dest->query("short")) dir=dest->query("short");
else dir = arg;
if( me->is_fighting() ) {
if (ANNIE_D->check_buff(me,"lockfield") >= 1)
{
tell_object(me,YEL"你眼前的景物似真似幻,游移不定,难以确定道路究竟是在何方。\n"NOR);
me->process_gmcp(room_info,"Move","Info");
return 0;
}
if (me->query_temp("timer/no_escape") > time()){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你现在不能逃跑!\n");
}
// 每3个heart_beat里只有一次逃跑的尝试可能成功。
if (me->query_temp("marks/escape") + 6 > time()) {
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你被挡了回来。\n");
}
if(check_flee(me, dir) == 0) {
me->set_temp("marks/escape",time());
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你被挡了回来。\n");
}
if (me->query("timer/insurance") + 259200 < time())
drop_things(me);
if (me->query("fleeout_message")) {
mout = replace_string( me->query("fleeout_message"), "$d", dir );
mout = mout + "。\n";
}
else
mout = "往" + dir + "落荒而逃了。\n";
if (me->query("fleein_message"))
min = me->query("fleein_message") + "。\n";
else
min = "跌跌撞撞地跑了过来,模样有些狼狈。\n";
} else {
// Let's add this messages here to make go and come more interesting...
if( mout = me->query("leave_msg"))
mout = "往" + dir + mout +"。\n";
else
mout = "往" + dir + "离开。\n";
if( min = me->query("arrive_msg") )
min = min + "。\n";
else
min = "走了过来。\n";
}
if (userp(me))
if (obj->query("underwater") > me->query_skill("swimming",1)){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你的游泳技能太差,没法过去呀(需要技能"+obj->query("underwater")+"级)\n");
}
if (!userp(me) && obj->query("NONPC"))
return notify_fail("你不可去那里。\n");
else if( function_exists("valid_enter", obj) && !obj->valid_enter(me)){
me->process_gmcp(room_info,"Move","Info");
return notify_fail("你不可去别人的私宅。\n");
}
if(!me->is_ghost())
if( me->query("self_go_msg") ) // this is for 自定义的不带主语的离开
message( "vision", me->query("leave_msg")+"\n", environment(me), ({me}) );
else if (me->query("env/invisibility"))
message("vision","似乎有什么东西一闪后不知向什么方向去了。\n",environment(me),({me}));
else message( "vision", me->name() + mout, environment(me), ({me}) );
if( me->move(obj) ) {
me->remove_all_enemy();
if(!me->is_ghost())
if( me->query("self_go_msg") ) // this is for 自定义的不带主语的进入
message( "vision", me->query("arrive_msg")+"\n", environment(me), ({me}) );
else if(me->query("env/invisibility"))
message("vision","似乎有什么东西闪了进来。\n",environment(me),({me}));
else
message( "vision", me->name()+ min, environment(me), ({me}) );
me->set_temp("pending", 0);
if(env)
if(environment(me) != env) {
all_inventory(env)->follow_me(me, arg);
}
room_info=([
"short":remove_ansi(environment(me)->query("short")),
"dirs":keys(environment(me)->query("exits")),
]);
me->process_gmcp(room_info,"Room","Info");
return 1;
}
if(userp(me))
me->process_gmcp(room_info,"Move","Info");
return 0;
}
void do_flee(object me) {
mapping exits;
string *directions;
if(!environment(me) || !living(me)) {
return;
}
exits = environment(me)->query("exits");
if(!mapp(exits) || !sizeof(exits)) {
return;
}
directions = keys(exits);
if (!me->query_temp("no_flee_msg"))
tell_object(me, "看来该找机会逃跑了...\n");
main(me, directions[random(sizeof(directions))]);
}
int help(object me) {
write(@HELP
[0;1;37m────────────────────────────────[0m
[0;1;36m指令格式 : go <方向>[0m
[0;1;37m────────────────────────────────[0m
让你往指定的方向移动。
你可以在战斗中用此指令尝试逃离当前房间,
1。逃离的几率直接取决于战斗双方的相对敏捷度
2。在对手忙乱(busy)时你的逃跑几率增大40%
3。每三个战斗回合只能有一次逃跑尝试可能成功
(也就是说,即使你在六秒钟内连着输入100个go,系统只根据第一个来判断)
4。在低等级时(L40前)增加逃跑几率10%-25%
数值计算及说明:a = 逃跑者速度;b = 敌人速度
当random(a + b ) < b 时,逃跑失败
1.如果敌人处在昏迷状态,逃跑必然成功
2.如果敌人经验值低于逃跑者的20%,逃跑必然成功
3.如果a>2b,逃跑必然成功
4.如果敌人处在忙乱状态,b*60%
5.如果逃跑者等级低于30,a*2
6.如果逃跑者等级低于40,a*2
[0;1;37m────────────────────────────────[0m
HELP
);
return 1;
}
关键代码
mapping room_info;
room_info=([]);
// 移动失败时增加
me->process_gmcp(room_info,"Move","Info");
//移动成功时增加
room_info=([
"short":remove_ansi(environment(me)->query("short")),
"dirs":keys(environment(me)->query("exits")),
]);
me->process_gmcp(room_info,"Room","Info");
配合上面go代码可以很好理解。
以上为mudlib改造
以下为mudlet内修改
找到mudlet触发器 在generic_mapper里把English Trigger Group | Russian Trigger Group | Chinese Trigger Group 全部禁用,onNewLine Trigger | Tab Trigger保持启用。
找到脚本generic_mapper
增加条目my_vitals_function,注册event handlers : gmcp.Room.Info
下面添加代码
function my_vitals_function()
map.prompt.room=gmcp.Room.Info.short
raiseEvent("onNewRoom",table.concat(gmcp.Room.Info.dirs," ") or "")
end
增加条目MoveFail,注册event handlers : gmcp.Move.Info
下面添加代码
function MoveFail()
raiseEvent("onMoveFail")
end
至此改造全部完成 点击mudlet上面地图按钮
命令行输入start mapping 地区名称就可以完成记录地图信息了
更多使用方法可以输入map help查看 相关代码截图已经打包发到群内