跳转至内容
  • 欢迎
  • 版块
  • 最新
  • 标签
  • 热门
  • 用户
  • 群组
皮肤
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • 默认(不使用皮肤)
  • 不使用皮肤
折叠
品牌标识

Hellclient 社区

  1. 主页
  2. Script脚本
  3. 深入浅出制作全自动Mud机器人-移动确认

深入浅出制作全自动Mud机器人-移动确认

已定时 已固定 已锁定 已移动 Script脚本
全自动机器人代码范例
1 帖子 1 发布者 7 浏览
  • 从旧到新
  • 从新到旧
  • 最多赞同
回复
  • 在新帖中回复
登录后回复
此主题已被删除。只有拥有主题管理权限的用户可以查看。
  • jarlyynJ 离线
    jarlyynJ 离线
    jarlyyn
    编写于 最后由 编辑
    #1

    在开始制作一个Mud机器人的移动模块之前,首先我们先要解决移动确认,也就是判断成功进入一个房间的问题。

    稍微延展点的话,就是解析当前房间的信息

    • 确定房间信息开始
    • 抓取房间名和其他信息
    • 抓取房间描述
    • 抓取房间出口
    • 抓取房间内对象
    • 确定房间信息结束

    本文章以我newhelljs的解析房间代码为例

    代码地址

    房间信息开始

    一般房间信息开始未必是一个很明确的信号。

    部分mud可能对房间有特殊的格式。但很多Mud单纯就是一个顶格不带特殊标点的短剧。

    所以我在处理房间时是分为两个部分

    第一是普通房间,比如

    ^[^,。!:.『』【】…“”??>.]{2,10}$
    

    然后这里我使用了一个Filter的概念,就是不直接抛事件,而是在进行了预处理后,符合条件时才抛事件。对应的代码是:

        App.Engine.SetFilter("core.normalroomname", function (event) {
            let words = App.History.CurrentOutput.Words
            if (words.length == 1 && words[0].Color != "" && words[0].Bold == true) {
                App.RaiseEvent(event)
            }
        })
    

    进行了简单的视觉判断,单色,非普通色,加粗。

    除了这个通用标准外,有特殊的出发可以直接抛房间名事件。

    在这里很明显,我是一个可能判断,并不能保证100%匹配。

    所以我并没有确定出现疑似房间名的信息就进入房间。

    出现疑似房间名我只是把已经抓取的房间描述清空,记录最后一个房间名,直到确定进入房间在把这些转化为当前房间信息。

    过滤干扰项

    我在代码里把所有季节相关的干扰项都记录在了"data/natures.txt"文件里,并进行了排除。

    这是为了抓取数据做快照而作的准备。

    如果你不需要抓取描述,可以不做这个处理。

    出口信息

    大部分Mud,出口信息都是比较统一,标准的,所以可以作为真正确认进入房间的信号

    我的代码里,就是在抓取到出口信息后,确认之前抓起的房间名和描述有效,开始抓取房间对象列表。

    如果你玩的Mud的代码比较复杂,这里可能有更多的处理。

    对象列表

    我这里主要是将对象可能的几个形态都列了出来,统一插入Room对象的 Object列表中。

    遇到的第一个不符合条件的行,就确认房间结束。

    这个主要还是看wiz怎么处理,有时候还会需要做特殊的处理。

        App.BindEvent("core.onexit", App.Core.Room.OnExit)
        let matcherOnHeal = /^  (\S{2,8})正坐在地下(.+)。$/
        let matcherOnYanlian = /^  (\S{2,8})正在演练招式。$/
        let matcherOnObj = /^  ((\S+) )?(\S*[「\(].+[\)」])?(\S+)\(([^\(\)]+)\)( \[.+\])?(( <.+>)*)$/
        //处理得到出口之后的信息(npc和道具列表)的计划
        var PlanOnExit = new App.Plan(App.Positions.Connect,
            function (task) {
                task.AddTrigger(matcherOnObj, function (trigger, result, event) {
                    let item = new objectModule.Object(result[4], result[5], App.History.CurrentOutput).
                        WithParam("身份", result[2]).
                        WithParam("外号", result[3]).
                        WithParam("描述", result[6] || "").
                        WithParam("状态", result[7] || "").
                        WithParam("动作", "")
                    App.Map.Room.Data.Objects.Append(item)
                    event.Context.Set("core.room.onobject", true)
                    return true
                })
                task.AddTrigger(matcherOnHeal, function (trigger, result, event) {
                    let item = new objectModule.Object(result[1], "", App.History.CurrentOutput).
                        WithParam("动作", result[2])
                    App.Map.Room.Data.Objects.Append(item)
                    event.Context.Set("core.room.onobject", true)
                    return true
                })
                task.AddTrigger(matcherOnYanlian, function (trigger, result, event) {
                    let item = new objectModule.Object(result[1], "", App.History.CurrentOutput).
                        WithParam("动作", "演练招式")
                    App.Map.Room.Data.Objects.Append(item)
                    event.Context.Set("core.room.onobject", true)
                    return true
                })
    
                task.AddCatcher("line", function (catcher, event) {
                    let output = event.Data.Output
                    if (output.length > 2 && output.startsWith("  ") && output[2] != " ") {
                        return true
                    }
                    //未匹配过的行代表npc和道具结束
                    return event.Context.Get("core.room.onobject")
                })
            }, function (result) {
                if (result.Type != "cancel") {
                    if (App.Map.Room.Name && !App.Map.Room.ID) {
                        let idlist = App.Map.Data.RoomsByName[App.Map.Room.Name]
                        if (idlist && idlist.length == 1) {
                            App.Map.Room.ID = idlist[0]
                        }
                    }
                    App.RaiseEvent(new App.Event("core.roomentry"))
                }
            })
    

    忽略信号

    一般来说,会有两种情况需要忽略移动确认的信号。

    第一种是MUD的干扰。Mud的Wiz可能能会设置一个类似进入房间的干扰选项。这个需要在代码里进行排除,具体实现要看Mud的设置。

    第二种是主动的Look。

    我在我的移动库做了特殊处理

            EnterNewRoom(room) {
                if (!room) {
                    room = new Room()
                }
                let oroom = this.Room
                this.Room = room
                if (oroom.Keep) {
                    if (oroom.ID) {
                        this.Room.ID = oroom.ID
                    }
                    this.Room.Keeping = true
                }
                this.Room.Keep = false
                return this.Room
            }
            OnWalking() {
                if (!this.Room.Keeping) {
                    this.Position.StartNewTerm()
                }
                if (this.Move != null) {
                    this.Move.OnWalking(this)
                }
            
    

    在Room有Keep属性时,不做彻底的清理处理,并不会触发对应的移动动作。

    封装事件

    由于Room处理是一个很复杂的工作。

    所以正常情况下,有一个专门的Room处理函数进行处理,处理完毕后抛出事件通知需要后续操作的模块。

    这样才能最大的程度的解耦合,并保证房间处理信息的内聚。

    不做切割的话,很容易随着房间信息格式的调整,把整个代码搅乱。

    1 条回复 最后回复
    • jarlyynJ jarlyyn 被引用 于这个主题
    回复
    • 在新帖中回复
    登录后回复
    • 从旧到新
    • 从新到旧
    • 最多赞同


    • 登录

    • 没有帐号? 注册

    • 登录或注册以进行搜索。
    Powered by Herbrhythm.
    • 第一个帖子
      最后一个帖子
    0
    • 欢迎
    • 版块
    • 最新
    • 标签
    • 热门
    • 用户
    • 群组