|  | 
 
 
 楼主|
发表于 2024-11-17 00:15:36
|
显示全部楼层 
| 首先让我们找到移动的代码,这个我熟悉,cmd/std/go.c 
 把拉巴拉一段战斗逃跑的判断,然后
 恩,好理解,把当前对象移动到dest下。
 
 这里mudos是这样的,所有的东西都是obejct,都是平级。obecjt下可以有子元素,就是道具。这样,一个道具即可以在room里,也可以在玩家身上,也可以在玩家身上的容器里,也可以在房间的容器里。大家都是对象,平级,都能装。
 
 然后找move方法的定义
 
 恩,在feature/move.c里
 
 一堆负重的判断,然后调用了一个 代码
 
 
 恩,这个我看文档看到过,是一个efun(官方api),让我们打开页面看看,继续水一点
 
 https://www.fluffos.info/zh-CN/efun/move_object.html
 
 移动当前对象到环境 `dest`,移动后会触发当前对象和目标环境及其中对象的 init() 方法。继续水,但是init不是初始化么,为啥移动会初始化一下?不管了,继续爬文档。
 熟练的打开文档https://www.fluffos.info/zh-CN/apply/object/init.html
 然后,然后,然后,我被硬控了几秒
 当 MUDLIB 移动对象 `A` 进入对象 `B`时,游戏驱动的 move_object() 外部函数会做以下行为:1. 如果 `A` 是生物(living),让 `A` 呼叫 `B` 的 init() 方法。2. 不管 `A` 是否是生物,让 `B` 中的所有生物呼叫 `A` 的 init() 方法。3. 如果 `A 是生物,让 `A 呼叫 `B` 中所有对象的 init() 方法。1.我还能理解,让移动入的元素和房间/容器交互下。2和3是什么鬼?和房间/容器所有的容器都交互下,然后再被房间里所有的容器交互下?这是啥,连还尸爆么?
 看的我一脸蒙蔽,爬下源代码
 efun我知道,直接搜f_move_object()就行
 调用的是src/package/core/efuns_main.cc里的
 然后move_object方法是src/internal/base/simulate.cc里复制代码#ifdef F_MOVE_OBJECT
void f_move_object() {
  object_t *o1, *o2;
  /* get destination */
  if (sp->type == T_OBJECT) {
    o2 = sp->u.ob;
  } else {
    if (!(o2 = find_object(sp->u.string)) || !object_visible(o2)) {
      error("move_object failed: could not find destination\n");
    }
  }
  if ((o1 = current_object)->flags & O_DESTRUCTED) {
    error("move_object(): can't move a destructed object\n");
  }
  move_object(o1, o2);
  pop_stack();
}
复制代码void move_object(object_t *item, object_t *dest) {
  object_t **pp, *ob;
  save_command_giver(command_giver);
  /* Recursive moves are not allowed. */
  for (ob = dest; ob; ob = ob->super) {
    if (ob == item) {
      error("Can't move object inside itself.\n");
    }
  }
#ifndef NO_SHADOWS
  if (item->shadowing) {
    error("Can't move an object that is shadowing.\n");
  }
#endif
  if (!CONFIG_INT(__RC_NO_RESETS__) && CONFIG_INT(__RC_LAZY_RESETS__)) {
    try_reset(dest);
  }
#ifndef NO_LIGHT
  add_light(dest, item->total_light);
#endif
  if (item->super) {
    int okay = 0;
    remove_sent(item->super, item);
    remove_sent(item, item->super);
#ifndef NO_LIGHT
    add_light(item->super, -item->total_light);
#endif
    for (pp = &item->super->contains; *pp;) {
      if (*pp != item) {
        remove_sent(item, *pp);
        remove_sent(*pp, item);
        pp = &(*pp)->next_inv;
        continue;
      }
      /*
       * unlink object from original inventory list
       */
      *pp = item->next_inv;
      okay = 1;
    }
#ifdef DEBUG
    if (!okay) {
      fatal("Failed to find object /%s in super list of /%s.\n", item->obname, item->super->obname);
    }
#endif
  }
  /*
   * link object into target's inventory list
   */
  item->next_inv = dest->contains;
  dest->contains = item;
  item->super = dest;
  setup_new_commands(dest, item);
  restore_command_giver();
}
恩,明显道具是个链表,里面有个不起眼的 setup_new_commands
 让我再找一下,在src/packages/core/add_action里(话说从内部包引用efun包,这合理么?):
 还真是互相交互两边啊,这不是性能炸弹么。复制代码void setup_new_commands(object_t *dest, object_t *item) {
  object_t *next_ob, *ob;
  /*
   * Setup the new commands. The order is very important, as commands in
   * the room should override commands defined by the room. Beware that
   * init() in the room may have moved 'item' !
   *
   * The call of init() should really be done by the object itself (except in
   * the -o mode). It might be too slow, though :-(
   */
  if (item->flags & O_ENABLE_COMMANDS) {
    save_command_giver(item);
    (void)apply(APPLY_INIT, dest, 0, ORIGIN_DRIVER);
    restore_command_giver();
    if (item->super != dest) {
      return;
    }
  }
  /*
   * Run init of the item once for every present user, and for the
   * environment (which can be a user).
   */
  for (ob = dest->contains; ob; ob = next_ob) {
    next_ob = ob->next_inv;
    if (ob == item) {
      continue;
    }
    if (ob->flags & O_DESTRUCTED) {
      error("An object was destructed at call of " APPLY_INIT "()\n");
    }
    if (dest != ob->super) {
      error("An object was moved at call of " APPLY_INIT "()\n");
    }
    if (ob->flags & O_ENABLE_COMMANDS) {
      save_command_giver(ob);
      (void)apply(APPLY_INIT, item, 0, ORIGIN_DRIVER);
      restore_command_giver();
      if (dest != item->super) {
        return;
      }
    }
    if (item->flags & O_DESTRUCTED) { /* marion */
      error("The object to be moved was destructed at call of " APPLY_INIT "()\n");
    }
    if (ob->flags & O_DESTRUCTED) { /* Alaron */
      error("An object was destructed at call of " APPLY_INIT "()\n");
    }
    if (item->flags & O_ENABLE_COMMANDS) {
      save_command_giver(item);
      (void)apply(APPLY_INIT, ob, 0, ORIGIN_DRIVER);
      restore_command_giver();
      if (dest != item->super) {
        return;
      }
    }
  }
  if (dest->flags & O_DESTRUCTED) { /* marion */
    error("The destination to move to was destructed at call of " APPLY_INIT "()\n");
  }
  if (item->flags & O_DESTRUCTED) { /* Alaron */
    error("The object to be moved was destructed at call of " APPLY_INIT "()\n");
  }
  if (dest->flags & O_ENABLE_COMMANDS) {
    save_command_giver(dest);
    (void)apply(APPLY_INIT, item, 0, ORIGIN_DRIVER);
    restore_command_giver();
  }
}
再让我们找个文件看看init()一般是干什么的。
 
 复制代码void init()
{
        object me;
        
        ::init();
        if (interactive(me = this_player()))
        {
                remove_call_out("greeting");
                call_out("greeting", 1, me);
        }
        me->delete_temp("decide_withdraw");
        me->delete_temp("demolish_room");
        add_action("do_stop", "stop");
        add_action("do_answer", "answer");
        add_action("do_desc", "desc");
        add_action("do_show", "show");
        add_action("do_changename", "changename");
        add_action("do_changeid",   "changeid");
        add_action("do_changetype", "changetype");
        add_action("do_changedesc", "changedesc");
        add_action("do_finish", "finish");
        add_action("do_finish", "ok");
        add_action("do_withdraw", "withdraw");
        add_action("do_withdraw", "chexiao");
        add_action("decide_withdraw", "decide");
        add_action("do_demolish", "demolish");
        // 如果来的是有资格处理表单的巫师就增加处理表单的命令
        if (wizardp(me) && wiz_level(me) >= WIZLEVEL)
        {
                add_action("do_help", "help");
                add_action("do_list", "list");
                add_action("do_type", "type");
                add_action("do_agree", "agree");
                add_action("do_reject", "reject");
                add_action("do_delete", "delete");
        }
}
好家伙,是为了绑临时指令啊。
 话说每走一步,捡个东西,丢个东西/放个东西到包裹里,都要这样来一圈,好扯啊。
 这init()函数,不是正常应该都为空,不正常情况采取使用么。
 我深度怀疑,北侠的移动指令这么容易上榜,可能就是和init优点重,或者addaction部分太重可能优点关系。
 
 | 
 |